Análise Exploratória de Dados de Empréstimo
Introdução
Este projeto consiste em realizar uma EDA (Análise Exloratória dos Dados) a partir dos dados fornecidos pela Prosper. Esse conjunto de dados faz parte das recomendações da Udacity para este projeto.
A Prosper é uma empresa fundada em 2005 com o objetivo de facilitar empréstimos para o mercado dos Estados Unidos. Essa iniciativa já atingiu mais de 15 bilhões de dólares em empréstimos para mais de 920000 pessoas. Prosper
O conjunto de dados analisado neste projeto é fornecido por esta empresa e mais sobre o seu conteúdo será abordado futuramente.
Para esta análise serão necessárias as seguintes bibliotecas:
library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
Iniciando a Análise
Primeiro é necessário carregar os dados a partir do csv. Neste projeto chamaremos estes dados de “ld” em referência a loan dataset para facilitar. Em seguida será exibida a estrutura desse conjunto de dados obtendo a quantidade de variáveis e de observações.
ld <- read.csv('prosperLoanData.csv')
ld <- read.csv('prosperLoanData.csv')
str(ld)
'data.frame': 113937 obs. of 81 variables:
$ ListingKey : Factor w/ 113066 levels "00003546482094282EF90E5",..: 7180 7193 6647 6669 6686 6689 6699 6706 6687 6687 ...
$ ListingNumber : int 193129 1209647 81716 658116 909464 1074836 750899 768193 1023355 1023355 ...
$ ListingCreationDate : Factor w/ 113064 levels "2005-11-09 20:44:28.847000000",..: 14184 111894 6429 64760 85967 100310 72556 74019 97834 97834 ...
$ CreditGrade : Factor w/ 9 levels "","A","AA","B",..: 5 1 8 1 1 1 1 1 1 1 ...
$ Term : int 36 36 36 36 36 60 36 36 36 36 ...
$ LoanStatus : Factor w/ 12 levels "Cancelled","Chargedoff",..: 3 4 3 4 4 4 4 4 4 4 ...
$ ClosedDate : Factor w/ 2803 levels "","2005-11-25 00:00:00",..: 1138 1 1263 1 1 1 1 1 1 1 ...
$ BorrowerAPR : num 0.165 0.12 0.283 0.125 0.246 ...
$ BorrowerRate : num 0.158 0.092 0.275 0.0974 0.2085 ...
$ LenderYield : num 0.138 0.082 0.24 0.0874 0.1985 ...
$ EstimatedEffectiveYield : num NA 0.0796 NA 0.0849 0.1832 ...
$ EstimatedLoss : num NA 0.0249 NA 0.0249 0.0925 ...
$ EstimatedReturn : num NA 0.0547 NA 0.06 0.0907 ...
$ ProsperRating..numeric. : int NA 6 NA 6 3 5 2 4 7 7 ...
$ ProsperRating..Alpha. : Factor w/ 8 levels "","A","AA","B",..: 1 2 1 2 6 4 7 5 3 3 ...
$ ProsperScore : num NA 7 NA 9 4 10 2 4 9 11 ...
$ ListingCategory..numeric. : int 0 2 0 16 2 1 1 2 7 7 ...
$ BorrowerState : Factor w/ 52 levels "","AK","AL","AR",..: 7 7 12 12 25 34 18 6 16 16 ...
$ Occupation : Factor w/ 68 levels "","Accountant/CPA",..: 37 43 37 52 21 43 50 29 24 24 ...
$ EmploymentStatus : Factor w/ 9 levels "","Employed",..: 9 2 4 2 2 2 2 2 2 2 ...
$ EmploymentStatusDuration : int 2 44 NA 113 44 82 172 103 269 269 ...
$ IsBorrowerHomeowner : Factor w/ 2 levels "False","True": 2 1 1 2 2 2 1 1 2 2 ...
$ CurrentlyInGroup : Factor w/ 2 levels "False","True": 2 1 2 1 1 1 1 1 1 1 ...
$ GroupKey : Factor w/ 707 levels "","00343376901312423168731",..: 1 1 335 1 1 1 1 1 1 1 ...
$ DateCreditPulled : Factor w/ 112992 levels "2005-11-09 00:30:04.487000000",..: 14347 111883 6446 64724 85857 100382 72500 73937 97888 97888 ...
$ CreditScoreRangeLower : int 640 680 480 800 680 740 680 700 820 820 ...
$ CreditScoreRangeUpper : int 659 699 499 819 699 759 699 719 839 839 ...
$ FirstRecordedCreditLine : Factor w/ 11586 levels "","1947-08-24 00:00:00",..: 8639 6617 8927 2247 9498 497 8265 7685 5543 5543 ...
$ CurrentCreditLines : int 5 14 NA 5 19 21 10 6 17 17 ...
$ OpenCreditLines : int 4 14 NA 5 19 17 7 6 16 16 ...
$ TotalCreditLinespast7years : int 12 29 3 29 49 49 20 10 32 32 ...
$ OpenRevolvingAccounts : int 1 13 0 7 6 13 6 5 12 12 ...
$ OpenRevolvingMonthlyPayment : num 24 389 0 115 220 1410 214 101 219 219 ...
$ InquiriesLast6Months : int 3 3 0 0 1 0 0 3 1 1 ...
$ TotalInquiries : num 3 5 1 1 9 2 0 16 6 6 ...
$ CurrentDelinquencies : int 2 0 1 4 0 0 0 0 0 0 ...
$ AmountDelinquent : num 472 0 NA 10056 0 ...
$ DelinquenciesLast7Years : int 4 0 0 14 0 0 0 0 0 0 ...
$ PublicRecordsLast10Years : int 0 1 0 0 0 0 0 1 0 0 ...
$ PublicRecordsLast12Months : int 0 0 NA 0 0 0 0 0 0 0 ...
$ RevolvingCreditBalance : num 0 3989 NA 1444 6193 ...
$ BankcardUtilization : num 0 0.21 NA 0.04 0.81 0.39 0.72 0.13 0.11 0.11 ...
$ AvailableBankcardCredit : num 1500 10266 NA 30754 695 ...
$ TotalTrades : num 11 29 NA 26 39 47 16 10 29 29 ...
$ TradesNeverDelinquent..percentage. : num 0.81 1 NA 0.76 0.95 1 0.68 0.8 1 1 ...
$ TradesOpenedLast6Months : num 0 2 NA 0 2 0 0 0 1 1 ...
$ DebtToIncomeRatio : num 0.17 0.18 0.06 0.15 0.26 0.36 0.27 0.24 0.25 0.25 ...
$ IncomeRange : Factor w/ 8 levels "$0","$1-24,999",..: 4 5 7 4 3 3 4 4 4 4 ...
$ IncomeVerifiable : Factor w/ 2 levels "False","True": 2 2 2 2 2 2 2 2 2 2 ...
$ StatedMonthlyIncome : num 3083 6125 2083 2875 9583 ...
$ LoanKey : Factor w/ 113066 levels "00003683605746079487FF7",..: 100337 69837 46303 70776 71387 86505 91250 5425 908 908 ...
$ TotalProsperLoans : int NA NA NA NA 1 NA NA NA NA NA ...
$ TotalProsperPaymentsBilled : int NA NA NA NA 11 NA NA NA NA NA ...
$ OnTimeProsperPayments : int NA NA NA NA 11 NA NA NA NA NA ...
$ ProsperPaymentsLessThanOneMonthLate: int NA NA NA NA 0 NA NA NA NA NA ...
$ ProsperPaymentsOneMonthPlusLate : int NA NA NA NA 0 NA NA NA NA NA ...
$ ProsperPrincipalBorrowed : num NA NA NA NA 11000 NA NA NA NA NA ...
$ ProsperPrincipalOutstanding : num NA NA NA NA 9948 ...
$ ScorexChangeAtTimeOfListing : int NA NA NA NA NA NA NA NA NA NA ...
$ LoanCurrentDaysDelinquent : int 0 0 0 0 0 0 0 0 0 0 ...
$ LoanFirstDefaultedCycleNumber : int NA NA NA NA NA NA NA NA NA NA ...
$ LoanMonthsSinceOrigination : int 78 0 86 16 6 3 11 10 3 3 ...
$ LoanNumber : int 19141 134815 6466 77296 102670 123257 88353 90051 121268 121268 ...
$ LoanOriginalAmount : int 9425 10000 3001 10000 15000 15000 3000 10000 10000 10000 ...
$ LoanOriginationDate : Factor w/ 1873 levels "2005-11-15 00:00:00",..: 426 1866 260 1535 1757 1821 1649 1666 1813 1813 ...
$ LoanOriginationQuarter : Factor w/ 33 levels "Q1 2006","Q1 2007",..: 18 8 2 32 24 33 16 16 33 33 ...
$ MemberKey : Factor w/ 90831 levels "00003397697413387CAF966",..: 11071 10302 33781 54939 19465 48037 60448 40951 26129 26129 ...
$ MonthlyLoanPayment : num 330 319 123 321 564 ...
$ LP_CustomerPayments : num 11396 0 4187 5143 2820 ...
$ LP_CustomerPrincipalPayments : num 9425 0 3001 4091 1563 ...
$ LP_InterestandFees : num 1971 0 1186 1052 1257 ...
$ LP_ServiceFees : num -133.2 0 -24.2 -108 -60.3 ...
$ LP_CollectionFees : num 0 0 0 0 0 0 0 0 0 0 ...
$ LP_GrossPrincipalLoss : num 0 0 0 0 0 0 0 0 0 0 ...
$ LP_NetPrincipalLoss : num 0 0 0 0 0 0 0 0 0 0 ...
$ LP_NonPrincipalRecoverypayments : num 0 0 0 0 0 0 0 0 0 0 ...
$ PercentFunded : num 1 1 1 1 1 1 1 1 1 1 ...
$ Recommendations : int 0 0 0 0 0 0 0 0 0 0 ...
$ InvestmentFromFriendsCount : int 0 0 0 0 0 0 0 0 0 0 ...
$ InvestmentFromFriendsAmount : num 0 0 0 0 0 0 0 0 0 0 ...
$ Investors : int 258 1 41 158 20 1 1 1 1 1 ...
Como este conjunto de dados contém 81 variáveis, torna-se evidente que existem muitos dados. Então é importante decidir primeiro quais variáveis serão escolhidas para análise e em seguida realizar a limpeza dos dados.
Escolha e definição das variáveis e limpeza dos dados
Como eu não possuo conhecimento extenso sobre a área serão escolhidas variáveis que ao meu ver podem ser bastante úteis para a análise. Pode ser que variáveis importantes sejam deixadas de lado, mas a ideia aqui será descobrir a relação dessas variáveis em relação aos empréstimos. Dessa forma será possível retornar e alterar a escolha dessas variáveis caso se mostre necessário.
Será necessário consultar a definição das variáveis para que seja possível fazer a seleção.
- ListingCreationDate: Data da criação da listagem.
- Term: Duração do empréstimo (em meses).
- LoanStatus: Status que pode variar em: Cancelled, Chargedoff, Completed, Current, Defaulted, FinalPaymentInProgress, PastDue.
- BorrowerRate: Taxa de juros para quem empresta.
- EstimatedReturn: Retorno estimado no momento em que foi criado.
- ProsperScore: Sistema de pontuação usando os dados históricos da Prosper. A pontuação varia de 1-10, sendo 10 a melhor pontuação.
- ListingCategory: categoria do empréstimo divida nas seguintes categorias
- 0 - Not Available
- 1 - Debt Consolidation
- 2 - Home Improvement
- 3 - Business
- 4 - Personal Loan
- 5 - Student Use
- 6 - Auto
- 7 - Other
- 8 - Baby&Adoption
- 9 - Boat
- 10 - Cosmetic Procedure
- 11 - Engagement Ring
- 12 - Green Loans
- 13 - Household Expenses
- 14 - Large Purchases
- 15 - Medical/Dental
- 16 - Motorcycle
- 17 - RV
- 18 - Taxes
- 19 - Vacation
- 20 - Wedding Loans
- Occupation: Profissão do mutuário
- EmploymentStatus: Status do emprego no momento em que a listagem foi criada
- CreditScoreRangeLower: Menor valor de pontuação de crédito de empréstimo
- CreditScoreRangeUpper: Maior valor de pontuação de crédito de empréstimo
- CurrentDelinquencies: Número de contas atrasadas no momento
- AmountDelinquencies: Quantidade em dólares atrasadas
- DebttoIncomeRatio: Taxa de débito por renda
- StatedMonthlyIncome: Renda mensal declarada
- MonthlyLoanPayment: Pagamento mensal do empréstimo.
Das 81 variáveis foram selecionadas 16 que serão trabalhadas na análise.
# Altera o nome da coluna 17 para facilitar seu uso
names(ld)[17]<-paste("ListingCategory")
# Cria novo conjunto de dados apenas com as 18 variáveis escolhidas
ld_clean <- subset(ld, select = c(
ListingCreationDate,
Term,
LoanStatus,
BorrowerRate,
EstimatedReturn,
ProsperScore,
ListingCategory,
Occupation,
EmploymentStatus,
CreditScoreRangeLower,
CreditScoreRangeUpper,
CurrentDelinquencies,
AmountDelinquent,
DebtToIncomeRatio,
StatedMonthlyIncome,
MonthlyLoanPayment
))
# Converte factor para Date
ld_clean$ListingCreationDate <- as.Date(ld_clean$ListingCreationDate)
str(ld_clean)
'data.frame': 113937 obs. of 16 variables:
$ ListingCreationDate : Date, format: "2007-08-26" "2014-02-27" "2007-01-05" "2012-10-22" ...
$ Term : int 36 36 36 36 36 60 36 36 36 36 ...
$ LoanStatus : Factor w/ 12 levels "Cancelled","Chargedoff",..: 3 4 3 4 4 4 4 4 4 4 ...
$ BorrowerRate : num 0.158 0.092 0.275 0.0974 0.2085 ...
$ EstimatedReturn : num NA 0.0547 NA 0.06 0.0907 ...
$ ProsperScore : num NA 7 NA 9 4 10 2 4 9 11 ...
$ ListingCategory : int 0 2 0 16 2 1 1 2 7 7 ...
$ Occupation : Factor w/ 68 levels "","Accountant/CPA",..: 37 43 37 52 21 43 50 29 24 24 ...
$ EmploymentStatus : Factor w/ 9 levels "","Employed",..: 9 2 4 2 2 2 2 2 2 2 ...
$ CreditScoreRangeLower: int 640 680 480 800 680 740 680 700 820 820 ...
$ CreditScoreRangeUpper: int 659 699 499 819 699 759 699 719 839 839 ...
$ CurrentDelinquencies : int 2 0 1 4 0 0 0 0 0 0 ...
$ AmountDelinquent : num 472 0 NA 10056 0 ...
$ DebtToIncomeRatio : num 0.17 0.18 0.06 0.15 0.26 0.36 0.27 0.24 0.25 0.25 ...
$ StatedMonthlyIncome : num 3083 6125 2083 2875 9583 ...
$ MonthlyLoanPayment : num 330 319 123 321 564 ...
Ao observar a amostra dos dados podemos indicar que há quase 114000 observações, só que muitas delas parecem conter dados incompletos. Por este motivo iremos excluir entradas que possam estar faltando dados e possam compremeter a análise.
str(ld_clean)
'data.frame': 77557 obs. of 16 variables:
$ ListingCreationDate : Date, format: "2014-02-27" "2012-10-22" "2013-09-14" "2013-12-14" ...
$ Term : int 36 36 36 60 36 36 36 36 60 36 ...
$ LoanStatus : Factor w/ 12 levels "Cancelled","Chargedoff",..: 4 4 4 4 4 4 4 4 4 8 ...
$ BorrowerRate : num 0.092 0.0974 0.2085 0.1314 0.2712 ...
$ EstimatedReturn : num 0.0547 0.06 0.0907 0.0708 0.1107 ...
$ ProsperScore : num 7 9 4 10 2 4 9 11 7 4 ...
$ ListingCategory : int 2 16 2 1 1 2 7 7 1 1 ...
$ Occupation : Factor w/ 68 levels "","Accountant/CPA",..: 43 52 21 43 50 29 24 24 22 50 ...
$ EmploymentStatus : Factor w/ 9 levels "","Employed",..: 2 2 2 2 2 2 2 2 2 2 ...
$ CreditScoreRangeLower: int 680 800 680 740 680 700 820 820 640 680 ...
$ CreditScoreRangeUpper: int 699 819 699 759 699 719 839 839 659 699 ...
$ CurrentDelinquencies : int 0 4 0 0 0 0 0 0 1 0 ...
$ AmountDelinquent : num 0 10056 0 0 0 ...
$ DebtToIncomeRatio : num 0.18 0.15 0.26 0.36 0.27 0.24 0.25 0.25 0.12 0.18 ...
$ StatedMonthlyIncome : num 6125 2875 9583 8333 2083 ...
$ MonthlyLoanPayment : num 319 321 564 342 123 ...
- attr(*, "na.action")= 'exclude' Named int 1 3 12 18 22 40 41 43 47 60 ...
..- attr(*, "names")= chr "1" "3" "12" "18" ...
Essa limpeza foi capaz de reduzir o conjunto de dados para quase metade das observações.
Análise Univariada
ListingCreationDate

Pode se observar que a quantidade de empréstimos foi aumentando ao longo do tempo, mas algo impactou esse crescimento no final de 2012 e começo de 2013.
Term

Pela análise estatística e do gráfico pode-se observar que a maior parte dos empréstimos possuem duração de 36 meses, seguido por 60 meses e uma pequena parcela de 12 meses.
LoanStatus

Pode-se observar que a maior parte dos empréstimos se enquadram em “Current” e “Completed”. Dessa forma, os dados dos outros status ficam reduzidos e difíceis de serem observados. Portanto, a seguir esses dois status serão excluídos para que melhore a observação da proporção dos outros status.

Filtrando as cariáveis “Current” e “Completed” pode-se observar que o Status “Chargedoff” também possui uma grande quantidade de empréstimos.
BorrowerRate

Pode-se observar existem alguns valores mais presentes que se destacam. Porém a distribuição mais popular se encontra entre 10 e 20%.
EstimatedReturn

Esse gráfico consegue reprentar com certa fidelidade uma relação de distribuição normal com relação aos dados de retorno estimado apra cada empréstimo realizado. Com a maior concentração de seus valores em cerca de 0,9%. Curioso destacar que há retornos estimados com valores negativos.
ProsperScore

Essa relação também parece representar uma distribuição normal. Como se trata de uma avaliação própria da empresa será mais intieressante a exploração futura com relação a outras variáveis para determinar seu impacto.
ListingCategory
Esta categoria é tratada de forma diferente, porém vale lembrar que apesar de estarmos lidando com uma lista enumerada segue a seguir cada um de suas respectivas categorias:
0 - Not Available
1 - Debt Consolidation
2 - Home Improvement
3 - Business
4 - Personal Loan
5 - Student Use
6 - Auto
7 - Other
8 - Baby and Adoption
9 - Boat
10 - Cosmetic Procedure
11 - Engagement Ring
12 - Green Loans
13 - Household Expenses
14 - Large Purchases
15 - Medical/Dental
16 - Motorcycle
17 - RV
18 - Taxes
19 - Vacation
20 - Wedding Loans

Consolidação de Crédito é o principal motivo para que as pessoas busquem empréstimos na Prosper. Dessa forma a relação das outras categorias fica nebulosa. Por isso será criado um novo gráfico ignorando a Consolidação de Crédito para que seja possível comparar a relação com as outras categorias.
Agora já é possível observar que o segundo motivo para o empréstimo na Prosper é encaixado na categoria “Outros” o que é razoável já que essa é uma categoria genérica que engloba diversas outras categorias não catalogadas. Em seguida é “Melhoria Domiciliar”, “Negócios” e “Automóveis”.
Occupation

Dentre os resultados obtidos será feita uma filtragem com as profissões com “Others” , “Professional” e "" por serem ambíguas.

Em ordem decrescente, a maior quantidade de profissionais que pegam empréstimos da Prosper são Executivos, Programadores e Professores, respectivamente.
EmploymentStatus

Pode-se verificar que a maior parte dos empréstimos foram feitos com pessoas que estavam atualmente empregadas no memomento do empréstimo.
CreditScoreRangeLower e CreditScoreRangeUpper


Observando os gráficos pode-se observar que a distribuição é muito semelhante porém com um breve deslocamento a direita em relação a Variação mais alta. O que faz sentido por que os dois gráficos tratam de uma mesma variável porém com extremos diferentes. Pode-se evidenciar também que a maior concentração de pontuação mais baixa fica em torno do valor de 700 e o mais alto em torno de 719.
CurrentDelinquencies

Pode-se observar que a maior concentração de pessoas com muitas dívidas se encontra com poucas contas atrasadas. Com processo de filtragem pode-se observar melhor a variação com mais contas.

A filtragem ajuda a mostrar que a maior quantidade de pessoas possui menos contas. São poucas pessoas que estão atrasadas e possuem diversas contas.

Fazendo uma breve análise pode-se analisar que a maior parte dos clientes se concentra em clientes não atrasados.
print(count_delinquent/(count_delinquent+count_no_delinquent))
[1] 0.1313743
Tem-se cerca de 13.1% dos clientes atrasados.

Fazendo uma filtragem com apenas atrasados em mais de 10000 dólares é possível ver que tratam-se de poucas pessoas. Portanto a grande concentração de pessoas se destina a dívidas menores que 10000 dólares.
DebtToIncomeRatio

A maior parte dos clientes possui uma proporção de dívida e renda de 0.22%. Salvo alguma exceções. No gráfico torna-se difícil de enxergar essa relação. Portanto, será utilizada uma tranformação logarítmica para facilitar a visualização deste outros casos.

A situação de análise se restringe a valores próximos de 0.22%, mas não é um fator limitante. Existindo casos em que essa razão pode ser extrapolada.
StatedMonthlyIncome

Utilizando um corte máximo de 20000 mil dólares com renda mensal declarada gera-se o gráfico acima. COm os dados fornecidos pode-se afirmar que a maior concentração de renda está em torno de 5000 mil dóalres mensais.
MonthlyLoanPayment

A maior parte das dívidas mensais, no entanto, giram em torno de 160 e 300 dólares mensais. Que são valores aceitáveis quanto a possibilidade de pagamento.
Análise Bavariada
Encontrando Correlações
Para analisar as correlações para a análise bivariada serão feitos alguns testes antes de decidir quais relações serão aprofundadas a seguir.
Pearson's product-moment correlation
data: ld_clean$BorrowerRate and ld_clean$EstimatedReturn
t = 409.24, df = 77555, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.8244916 0.8289469
sample estimates:
cor
0.8267322
Pearson's product-moment correlation
data: ld_clean$ProsperScore and ld_clean$CreditScoreRangeLower
t = 116.88, df = 77555, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.3810005 0.3929681
sample estimates:
cor
0.3870006
Pearson's product-moment correlation
data: ld_clean$ProsperScore and ld_clean$CreditScoreRangeUpper
t = 116.88, df = 77555, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.3810005 0.3929681
sample estimates:
cor
0.3870006
Correlações:
- BorrowerRate e Estimated Return: 0.8267322
- ProsperScore e CreditScoreRangeLower: 0.3870006
- ProsperScore e CreditScoreRangeUpper: 0.3870006
Muitas das outras comparações apontaram valores de pontuação de correlação muito baixas e foram descartadas e outras utilizam tipos qualitativos e não quantitativos.
Portanto algumas das análises serão feitas de forma arbitrária para analisar a relação de cada variável.
BorrowerRate e EstimatedReturn

Há dois grandes padrões observados com estes dados. O primeiro deles é que as Taxas de Empréstimo e O Retorno estimado seguem camadas lineares e paralelas de forma bastante sutil. Enquanto ao mesmo tempo há uma concentração bastante grande de valores acumulados e com certa divergência de valores de Retorno Estimado entre 0.3 e 0.11 .
ListingCategory e Occupation

O que mais se destaca por esta análise é que o fator mais relevante para empréstimo é a categoria delas, que seguem o mesmo padrão para as mais diversas profissões em maior ou menos intensidade. Vale destacar que as profissões “Professional” e “Others” por serem mais genéricas e possuirem diversos dados com esta definiçãpo, apresenta uma forte marcação. Outra observação é a de que Estudantes de uma forma geral não possuem muitos empréstimos. Muito provavelmente por motivos financeiros, já que ao estudar torna-se menos propenso a dividir o tempo de dedicação com algum a atividade remunerada que garanta o cobrimento das parelas de um empréstimo. Por outro lado, Juízes, Investidores também são menos propensos a terem empréstimos. Por sua vez, acredito que pela natureza de se tratar de empregos que recebem alta remuneração há a menor busca de empréstimos.
Term e DebtToIncomeRatio

Nos 3 cenários observam-se características. A primeira é que a maior parte dos mutuários com tempo de empréstimo de 12 meses também possuem uma taxa menor de Dívida por Renda, o que significa que há uma relação de capacidade financeiro de prover o pagamento da dívida. A segunda é a variação gradual de Taxa de Dívida por Renda. Sendo este o caso mais com maior ocorrências e por último, o terceiro cenário em que há 60 meses de tempo de empréstimo, mas que aprensenta também uma taxa de Dívida por Renda maior.
StatedMonthlyIncome e ProsperScore

Pode-se observar que há uma leve inclinação para que uma quantidade maior de Renda Mensal Declarada ajude a ter uma pontuação maior na Prosper, mas ainda devem ser feitos análises mais extensivas para que possam se afirmar quaisquer conclusões sobre o real impacto desta variável.
ProsperScore e CreditScoreRangeLower

Esta análise também mostra uma leve relação entre a CreditScoreRangeLower e a ProsperScore com uma leve tendência de cresciemnto.
ProsperScore e CreditScoreRangeUpper

De forma análoga, a mesma relação pode ser observada quando se tratam das variáveis ProsperScore e CreditScoreRangeUpper.
Profissões e Pontuação Prosper

Uma breve análise consegue destacar algumas carreiras que conseguem obter pontuações maiores na Prosper dentre elas destacam-se Programador, Engenheiro Eletricista, Advogado, Doutor, Farmacêutico, Arquiteto, Investidor e Juíz. Em geral tratam-se de profissões bem remuneradas, o que pode ser um fator determinante para esta análise.
Análise Multivariada
Estimated Return, BorrowerRate e ProsperScore

Comparando agora a análise bivariada de Borrower Rate e Estimated Return com o ProsperScore é possível enxergar uma gradação bastante interessante para as relações de Borrower Rate e Estimated Return. Pode-se concluir que um dos fatores mais relevantes para a diferenciação é a nota da ProsperScore que concentra maiores pontuações quanto maior a Estimativa de Retorno, o que também viabiliza uma Taxa de Empréstimo Menor.
StatedMonthlyIncome, EstimatedReturn e ProsperScore

Nesta análise pode-se chegar a conclusão que valores de taxa de retorno negativas impactam na ProsperScore significativamente. Não significa que quanto maior a taxa de retorno maior a pontuação da ProsperScore, como pode-se evidenciar pela nuvem mesclada de dados entre taxas superiores a 0 e inferiores a 0.2. Porém, para taxas acima de 0.2 a ProsperScore sempre apresenta boas pontuações. Agora sobre a Renda Mensal Declarada não parece ter tantra influência na ProsperScore.
ListingCategory, DebtToIncomeRatio, ProsperScore

Esta análise não consegue atingir nenhuma conclusão por apresentar uma distribuição bastante bagunçada da ProsperScore.
Gráficos Finais e Resumo
Relação da Razão da Dívida por Renda Mensal por Taxa de Empréstimo para a Prosper Score

Este gráfico envolve a relação entre a Razão da Dívida por Renda Mensal, que ao longo de toda esta análise foi considerada uma variável bastante importante para determinar a possibilidade de cada mutuário ser capaz de quitar seu empréstimo, com a Taxa de Empréstimo, que é a taxa determinada para quem está emprestando este dinheiro ao mutuário. Essa relação consegue criar um gradiente com a pontuação da Prosper para cada mutuário.
A princípio é possível enxergar que há uma maior concentração de pontuação mais alta ao reduzir a Taxa de Empréstimo. Porém, não se torna distinto tão facilmente se a Razão de Dívida por Renda Mensal também influencia tanto a Pontuação da Prosper. Por isso, torna-se necessário o uso da reta para enxergar a tendência desses dados.
A conclusão é que maior será a Pontuação da Prosper quanto menor for a a razão da dívida por renda mensal do mutuário e quanto menor a taxa de empréstimo.
Renda Mensal Declarada, Estimativa de Retorno, ProsperScore

A análise de Renda Mensal Declarada e Estimativa de Retorno, apresetaram resultados bastante interessantes para a análise do Score da Prosper. Inicialmente podemos afirmar que não há influência da relação das duas variáveis em relação à pontuação da Prosper. Porém, olhando cuidadosamente, é possível enxergar que existem valores limitantes para a estimativa de retorno que criam faixas que podem criar separações entre 3 áreas distintitas. A primeira faixa delimita uma taxa de retorno acima ao valor de 0.18 que predominantemente possui apenas mutuários com pontuações mais altas na ProsperScore. A faixa inferior de -0.02 para baixo apresenta predominantemente mutuários com baixas pontuações na ProsperScore. Enquanto a camada central se encontra uma faixa com valores distintos e bastante misturados entre si. Sem poder afirmar uma relação com a renda mensal declarada. Muito provavelmente por ser muito mais provável de se determinar uma relação bruta da pontuação da Prosper quando comapra ao gráfico da análise anterior, já que estaria lidando com a variável em função da Razão entre a Dívida e a Renda mensal do mutuário. Portanto, maior renda não significa nada para a Pontução da Prosper, mas sim a relação dessa renda com a dívida em si.
DebtToIncomeRatio, Occupation, ProsperScore

A análise de Profissões por Renda Mensal Declarada vai possuir uma certa distribuição que acompanhará cada Profissão. Aglomerando essas informações com a pontuação da Prosper pode-se observar que maiores pontuações da Prosper estão distribuídas entre todas as profissões porém, algumas concentram uma quantidade maior. Era de se esperar que a Razão da Dívida e Renda Mensal fossem fatores fortes para essa pontuação, porém, pode-se enxergar que em algumas profissões existem mutuários com essa razão próxima de 0.2 que também aprensentam pontuações altas na Prosper.
Reflexão
Este projeto foi bastante interessante e tangencialmente incentiva o estudante a compreender os dados que estão sendo trabalhados. Por este mesmo motivo, a primeira dificuldade encontrada foi entender cada variável de maneira correta, já que eu não possuo background em como empréstimos funcionam, isso aliado aos termos todos em inglês agregou muito conhecimento buscando entender como tudo funcionava. Uma grande ajuda foi a planilha explicativa descrevendo cada variável e suas peculiaridades.
Em seguida foi um grande exercício lidar com este número de variáveis com tantos tipos diferentes e buscar compreender a melhor forma de lidar com as variáveis escolhidas.
Agora que o processo de análise chegou ao fim sobra um pouco de curiosidade de outras conclusões que poderiam ser obtidas lidando com mais variáveis. Das 81 variáveis presentes no conjunto de dados foram utilizadas apenas 16 delas. Dessa forma sobram muitas possibilidades de análises que poderiam ser feitas.
LS0tCnRpdGxlOiAiQW7DoWxpc2UgRXhwbG9yYXTDs3JpYSBkZSBEYWRvcyBkZSBFbXByw6lzdGltbyIKYXV0aG9yOiAiUm9kcmlnbyBUb3NoaWFraSBIb3JpZSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBBbsOhbGlzZSBFeHBsb3JhdMOzcmlhIGRlIERhZG9zIGRlIEVtcHLDqXN0aW1vCgojIyBJbnRyb2R1w6fDo28KCkVzdGUgcHJvamV0byBjb25zaXN0ZSBlbSByZWFsaXphciB1bWEgRURBIChBbsOhbGlzZSBFeGxvcmF0w7NyaWEgZG9zIERhZG9zKSBhIHBhcnRpciBkb3MgZGFkb3MgZm9ybmVjaWRvcyBwZWxhIFtQcm9zcGVyXShodHRwczovL3d3dy5wcm9zcGVyLmNvbS8pLiBFc3NlIGNvbmp1bnRvIGRlIGRhZG9zIGZheiBwYXJ0ZSBkYXMgW3JlY29tZW5kYcOnw7VlcyBkYSBVZGFjaXR5XShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9kb2N1bWVudC9kLzFqWDN2emtGdUZPQkdVcmxjUV9MYzNqRVpWbENfMnl5azN0Rklid0FJNUdRL2VkaXQpIHBhcmEgZXN0ZSBwcm9qZXRvLiAKCkEgUHJvc3BlciDDqSB1bWEgZW1wcmVzYSBmdW5kYWRhIGVtIDIwMDUgY29tIG8gb2JqZXRpdm8gZGUgZmFjaWxpdGFyIGVtcHLDqXN0aW1vcyBwYXJhIG8gbWVyY2FkbyBkb3MgRXN0YWRvcyBVbmlkb3MuIEVzc2EgaW5pY2lhdGl2YSBqw6EgYXRpbmdpdSBtYWlzIGRlIDE1IGJpbGjDtWVzIGRlIGTDs2xhcmVzIGVtIGVtcHLDqXN0aW1vcyBwYXJhIG1haXMgZGUgOTIwMDAwIHBlc3NvYXMuIFtQcm9zcGVyXShodHRwczovL3d3dy5wcm9zcGVyLmNvbS9hYm91dCkKCk8gY29uanVudG8gZGUgZGFkb3MgYW5hbGlzYWRvIG5lc3RlIHByb2pldG8gw6kgZm9ybmVjaWRvIHBvciBlc3RhIGVtcHJlc2EgZSBtYWlzIHNvYnJlIG8gc2V1IGNvbnRlw7pkbyBzZXLDoSBhYm9yZGFkbyBmdXR1cmFtZW50ZS4KClBhcmEgZXN0YSBhbsOhbGlzZSBzZXLDo28gbmVjZXNzw6FyaWFzIGFzIHNlZ3VpbnRlcyBiaWJsaW90ZWNhczoKCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdyaWQpCmBgYAoKCiMjIEluaWNpYW5kbyBhIEFuw6FsaXNlCgpQcmltZWlybyDDqSBuZWNlc3PDoXJpbyBjYXJyZWdhciBvcyBkYWRvcyBhIHBhcnRpciBkbyBjc3YuIE5lc3RlIHByb2pldG8gY2hhbWFyZW1vcyBlc3RlcyBkYWRvcyBkZSAibGQiIGVtIHJlZmVyw6puY2lhIGEgbG9hbiBkYXRhc2V0IHBhcmEgZmFjaWxpdGFyLgpFbSBzZWd1aWRhIHNlcsOhIGV4aWJpZGEgYSBlc3RydXR1cmEgZGVzc2UgY29uanVudG8gZGUgZGFkb3Mgb2J0ZW5kbyBhIHF1YW50aWRhZGUgZGUgdmFyacOhdmVpcyBlIGRlIG9ic2VydmHDp8O1ZXMuCgpgYGB7cn0KbGQgPC0gcmVhZC5jc3YoJ3Byb3NwZXJMb2FuRGF0YS5jc3YnKQpzdHIobGQpCmBgYAoKQ29tbyBlc3RlIGNvbmp1bnRvIGRlIGRhZG9zIGNvbnTDqW0gODEgdmFyacOhdmVpcywgdG9ybmEtc2UgZXZpZGVudGUgcXVlIGV4aXN0ZW0gbXVpdG9zIGRhZG9zLiBFbnTDo28gw6kgaW1wb3J0YW50ZSBkZWNpZGlyIHByaW1laXJvIHF1YWlzIHZhcmnDoXZlaXMgc2Vyw6NvIGVzY29saGlkYXMgcGFyYSBhbsOhbGlzZSBlIGVtIHNlZ3VpZGEgcmVhbGl6YXIgYSBsaW1wZXphIGRvcyBkYWRvcy4KCiMjIEVzY29saGEgZSBkZWZpbmnDp8OjbyBkYXMgdmFyacOhdmVpcyBlIGxpbXBlemEgZG9zIGRhZG9zCgpDb21vIGV1IG7Do28gcG9zc3VvIGNvbmhlY2ltZW50byBleHRlbnNvIHNvYnJlIGEgw6FyZWEgc2Vyw6NvIGVzY29saGlkYXMgdmFyacOhdmVpcyBxdWUgYW8gbWV1IHZlciBwb2RlbSBzZXIgYmFzdGFudGUgw7p0ZWlzIHBhcmEgYSBhbsOhbGlzZS4gUG9kZSBzZXIgcXVlIHZhcmnDoXZlaXMgaW1wb3J0YW50ZXMgc2VqYW0gZGVpeGFkYXMgZGUgbGFkbywgbWFzIGEgaWRlaWEgYXF1aSBzZXLDoSBkZXNjb2JyaXIgYSByZWxhw6fDo28gZGVzc2FzIHZhcmnDoXZlaXMgZW0gcmVsYcOnw6NvIGFvcyBlbXByw6lzdGltb3MuIERlc3NhIGZvcm1hIHNlcsOhIHBvc3PDrXZlbCByZXRvcm5hciBlIGFsdGVyYXIgYSBlc2NvbGhhIGRlc3NhcyB2YXJpw6F2ZWlzIGNhc28gc2UgbW9zdHJlIG5lY2Vzc8OhcmlvLiAKClNlcsOhIFtuZWNlc3PDoXJpbyBjb25zdWx0YXIgYSBkZWZpbmnDp8OjbyBkYXMgdmFyacOhdmVpc10oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMWdEeWlfTDRVdklyTFRFQzZXcmk1bmJhTW1rR21MUUJrLVl4M3owWERFdEkvZWRpdCkgcGFyYSBxdWUgc2VqYSBwb3Nzw612ZWwgZmF6ZXIgYSBzZWxlw6fDo28uCgotIExpc3RpbmdDcmVhdGlvbkRhdGU6IERhdGEgZGEgY3JpYcOnw6NvIGRhIGxpc3RhZ2VtLgotIFRlcm06IER1cmHDp8OjbyBkbyBlbXByw6lzdGltbyAoZW0gbWVzZXMpLgotIExvYW5TdGF0dXM6IFN0YXR1cyBxdWUgcG9kZSB2YXJpYXIgZW06IENhbmNlbGxlZCwgIENoYXJnZWRvZmYsIENvbXBsZXRlZCwgQ3VycmVudCwgRGVmYXVsdGVkLCBGaW5hbFBheW1lbnRJblByb2dyZXNzLCBQYXN0RHVlLgotIEJvcnJvd2VyUmF0ZTogVGF4YSBkZSBqdXJvcyBwYXJhIHF1ZW0gZW1wcmVzdGEuCi0gRXN0aW1hdGVkUmV0dXJuOiBSZXRvcm5vIGVzdGltYWRvIG5vIG1vbWVudG8gZW0gcXVlIGZvaSBjcmlhZG8uCi0gUHJvc3BlclNjb3JlOiBTaXN0ZW1hIGRlIHBvbnR1YcOnw6NvIHVzYW5kbyBvcyBkYWRvcyBoaXN0w7NyaWNvcyBkYSBQcm9zcGVyLiBBIHBvbnR1YcOnw6NvIHZhcmlhIGRlIDEtMTAsIHNlbmRvIDEwIGEgbWVsaG9yIHBvbnR1YcOnw6NvLgotIExpc3RpbmdDYXRlZ29yeTogY2F0ZWdvcmlhIGRvIGVtcHLDqXN0aW1vIGRpdmlkYSBuYXMgc2VndWludGVzIGNhdGVnb3JpYXMKICAgIC0gMCAtIE5vdCBBdmFpbGFibGUKICAgIC0gMSAtIERlYnQgQ29uc29saWRhdGlvbgogICAgLSAyIC0gSG9tZSBJbXByb3ZlbWVudAogICAgLSAzIC0gQnVzaW5lc3MKICAgIC0gNCAtIFBlcnNvbmFsIExvYW4KICAgIC0gNSAtIFN0dWRlbnQgVXNlCiAgICAtIDYgLSBBdXRvCiAgICAtIDcgLSBPdGhlcgogICAgLSA4IC0gQmFieSZBZG9wdGlvbgogICAgLSA5IC0gQm9hdAogICAgLSAxMCAtIENvc21ldGljIFByb2NlZHVyZQogICAgLSAxMSAtIEVuZ2FnZW1lbnQgUmluZwogICAgLSAxMiAtIEdyZWVuIExvYW5zCiAgICAtIDEzIC0gSG91c2Vob2xkIEV4cGVuc2VzCiAgICAtIDE0IC0gTGFyZ2UgUHVyY2hhc2VzCiAgICAtIDE1IC0gTWVkaWNhbC9EZW50YWwKICAgIC0gMTYgLSBNb3RvcmN5Y2xlCiAgICAtIDE3IC0gUlYKICAgIC0gMTggLSBUYXhlcwogICAgLSAxOSAtIFZhY2F0aW9uCiAgICAtIDIwIC0gV2VkZGluZyBMb2FucwotIE9jY3VwYXRpb246IFByb2Zpc3PDo28gZG8gbXV0dcOhcmlvCi0gRW1wbG95bWVudFN0YXR1czogU3RhdHVzIGRvIGVtcHJlZ28gbm8gbW9tZW50byBlbSBxdWUgYSBsaXN0YWdlbSBmb2kgY3JpYWRhCi0gQ3JlZGl0U2NvcmVSYW5nZUxvd2VyOiBNZW5vciB2YWxvciBkZSBwb250dWHDp8OjbyBkZSBjcsOpZGl0byBkZSBlbXByw6lzdGltbwotIENyZWRpdFNjb3JlUmFuZ2VVcHBlcjogTWFpb3IgdmFsb3IgZGUgcG9udHVhw6fDo28gZGUgY3LDqWRpdG8gZGUgZW1wcsOpc3RpbW8KLSBDdXJyZW50RGVsaW5xdWVuY2llczogTsO6bWVybyBkZSBjb250YXMgYXRyYXNhZGFzIG5vIG1vbWVudG8KLSBBbW91bnREZWxpbnF1ZW5jaWVzOiBRdWFudGlkYWRlIGVtIGTDs2xhcmVzIGF0cmFzYWRhcwotIERlYnR0b0luY29tZVJhdGlvOiBUYXhhIGRlIGTDqWJpdG8gcG9yIHJlbmRhIAotIFN0YXRlZE1vbnRobHlJbmNvbWU6IFJlbmRhIG1lbnNhbCBkZWNsYXJhZGEKLSBNb250aGx5TG9hblBheW1lbnQ6IFBhZ2FtZW50byBtZW5zYWwgZG8gZW1wcsOpc3RpbW8uCgpEYXMgODEgdmFyacOhdmVpcyBmb3JhbSBzZWxlY2lvbmFkYXMgMTYgcXVlIHNlcsOjbyB0cmFiYWxoYWRhcyBuYSBhbsOhbGlzZS4KCmBgYHtyfQojIEFsdGVyYSBvIG5vbWUgZGEgY29sdW5hIDE3IHBhcmEgZmFjaWxpdGFyIHNldSB1c28KbmFtZXMobGQpWzE3XTwtcGFzdGUoIkxpc3RpbmdDYXRlZ29yeSIpCgojIENyaWEgbm92byBjb25qdW50byBkZSBkYWRvcyBhcGVuYXMgY29tIGFzIDE4IHZhcmnDoXZlaXMgZXNjb2xoaWRhcwpsZF9jbGVhbiA8LSBzdWJzZXQobGQsIHNlbGVjdCA9IGMoCiAgICBMaXN0aW5nQ3JlYXRpb25EYXRlLAogICAgVGVybSwgCiAgICBMb2FuU3RhdHVzLAogICAgQm9ycm93ZXJSYXRlLCAKICAgIEVzdGltYXRlZFJldHVybiwgCiAgICBQcm9zcGVyU2NvcmUsCiAgICBMaXN0aW5nQ2F0ZWdvcnksCiAgICBPY2N1cGF0aW9uLCAKICAgIEVtcGxveW1lbnRTdGF0dXMsCiAgICBDcmVkaXRTY29yZVJhbmdlTG93ZXIsCiAgICBDcmVkaXRTY29yZVJhbmdlVXBwZXIsCiAgICBDdXJyZW50RGVsaW5xdWVuY2llcywKICAgIEFtb3VudERlbGlucXVlbnQsCiAgICBEZWJ0VG9JbmNvbWVSYXRpbywKICAgIFN0YXRlZE1vbnRobHlJbmNvbWUsIAogICAgTW9udGhseUxvYW5QYXltZW50CikpCgojIENvbnZlcnRlIGZhY3RvciBwYXJhIERhdGUKbGRfY2xlYW4kTGlzdGluZ0NyZWF0aW9uRGF0ZSA8LSBhcy5EYXRlKGxkX2NsZWFuJExpc3RpbmdDcmVhdGlvbkRhdGUpCgpzdHIobGRfY2xlYW4pCgoKYGBgCgpBbyBvYnNlcnZhciBhIGFtb3N0cmEgZG9zIGRhZG9zIHBvZGVtb3MgaW5kaWNhciBxdWUgaMOhIHF1YXNlIDExNDAwMCBvYnNlcnZhw6fDtWVzLCBzw7MgcXVlIG11aXRhcyBkZWxhcyBwYXJlY2VtIGNvbnRlciBkYWRvcyBpbmNvbXBsZXRvcy4gUG9yIGVzdGUgbW90aXZvIGlyZW1vcyBleGNsdWlyIGVudHJhZGFzIHF1ZSBwb3NzYW0gZXN0YXIgZmFsdGFuZG8gZGFkb3MgZSBwb3NzYW0gY29tcHJlbWV0ZXIgYSBhbsOhbGlzZS4KCmBgYHtyfQojIExpbXBhIGVudHJhZGFzIE5BCmxkX2NsZWFuIDwtIG5hLmV4Y2x1ZGUobGRfY2xlYW4pCnN0cihsZF9jbGVhbikKYGBgCgpFc3NhIGxpbXBlemEgZm9pIGNhcGF6IGRlIHJlZHV6aXIgbyBjb25qdW50byBkZSBkYWRvcyBwYXJhIHF1YXNlIG1ldGFkZSBkYXMgb2JzZXJ2YcOnw7Vlcy4gCgojIyBBbsOhbGlzZSBVbml2YXJpYWRhIAoKIyMjIExpc3RpbmdDcmVhdGlvbkRhdGUKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpxcGxvdChMaXN0aW5nQ3JlYXRpb25EYXRlLCBkYXRhID0gbGRfY2xlYW4sIHhsYWIgPSAiRGF0YSIsIHlsYWIgPSAiRW1wcsOpc3RpbW9zIiwgbWFpbiA9ICJRdWFudGlkYWRlIGRlIGVtcHLDqXN0aW1vcyBwb3IgZGF0YSIpIAogICAgCmBgYAoKUG9kZSBzZSBvYnNlcnZhciBxdWUgYSBxdWFudGlkYWRlIGRlIGVtcHLDqXN0aW1vcyBmb2kgYXVtZW50YW5kbyBhbyBsb25nbyBkbyB0ZW1wbywgbWFzIGFsZ28gaW1wYWN0b3UgZXNzZSBjcmVzY2ltZW50byBubyBmaW5hbCBkZSAyMDEyIGUgY29tZcOnbyBkZSAyMDEzLiAKCiMjIyBUZXJtCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzdW1tYXJ5KGxkX2NsZWFuJFRlcm0pCnFwbG90KFRlcm0sIGRhdGEgPSBsZF9jbGVhbiwgeGxhYiA9ICJUZW1wbyBlbSBNZXNlcyIsIHlsYWIgPSAiUXVhbnRpZGFkZSIsIG1haW4gPSAiUXVhbnRpZGFkZSBkZSB0ZW1wbyBkZSBlbXByw6lzdGltbyIpCmBgYAoKUGVsYSBhbsOhbGlzZSBlc3RhdMOtc3RpY2EgZSBkbyBncsOhZmljbyBwb2RlLXNlIG9ic2VydmFyIHF1ZSBhIG1haW9yIHBhcnRlIGRvcyBlbXByw6lzdGltb3MgcG9zc3VlbSBkdXJhw6fDo28gZGUgMzYgbWVzZXMsIHNlZ3VpZG8gcG9yIDYwIG1lc2VzIGUgdW1hIHBlcXVlbmEgcGFyY2VsYSBkZSAxMiBtZXNlcy4KCiMjIyBMb2FuU3RhdHVzCgpgYGB7cn0KCnN1bW1hcnkobGRfY2xlYW4kTG9hblN0YXR1cykKCmdncGxvdChsZF9jbGVhbiwgYWVzKExvYW5TdGF0dXMpKSArCiAgICBnZW9tX2JhcigpKwogICAgY29vcmRfZmxpcCgpICsgCiAgICBsYWJzKHggPSAiUXVhbnRpZGFkZSIsIHkgPSAiU3RhdHVzIGRlIEVtcHLDqXN0aW1vIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBlbXByw6lzdGltb3MgcG9yIFN0YXR1cyAiKQpgYGAKClBvZGUtc2Ugb2JzZXJ2YXIgcXVlIGEgbWFpb3IgcGFydGUgZG9zIGVtcHLDqXN0aW1vcyBzZSBlbnF1YWRyYW0gZW0gIkN1cnJlbnQiIGUgIkNvbXBsZXRlZCIuIERlc3NhIGZvcm1hLCBvcyBkYWRvcyBkb3Mgb3V0cm9zIHN0YXR1cyBmaWNhbSByZWR1emlkb3MgZSBkaWbDrWNlaXMgZGUgc2VyZW0gb2JzZXJ2YWRvcy4gUG9ydGFudG8sIGEgc2VndWlyIGVzc2VzIGRvaXMgc3RhdHVzIHNlcsOjbyBleGNsdcOtZG9zIHBhcmEgcXVlIG1lbGhvcmUgYSBvYnNlcnZhw6fDo28gZGEgcHJvcG9yw6fDo28gZG9zIG91dHJvcyBzdGF0dXMuCgpgYGB7cn0KZ2dwbG90KGZpbHRlcihsZF9jbGVhbiwgTG9hblN0YXR1cyAhPSAiQ3VycmVudCIgJgogICAgICAgICAgICAgICAgTG9hblN0YXR1cyAhPSAiQ29tcGxldGVkIiksCiAgICAgICAgICAgICAgICBhZXMoTG9hblN0YXR1cykpICsKICAgICAgICAgICAgICAgIGdlb21fYmFyKCkgKwogICAgICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMDAwMCwgMTAwMCkpICsKICAgICAgICAgICAgICAgIGNvb3JkX2ZsaXAoKSArCiAgICAgICAgICAgICAgICBsYWJzKHggPSAiUXVhbnRpZGFkZSIsIHkgPSAiU3RhdHVzIGRlIEVtcHLDqXN0aW1vIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBlbXByw6lzdGltb3MgcG9yIFN0YXR1cyIpCmBgYApGaWx0cmFuZG8gYXMgY2FyacOhdmVpcyAiQ3VycmVudCIgZSAiQ29tcGxldGVkIiBwb2RlLXNlIG9ic2VydmFyIHF1ZSBvIFN0YXR1cyAiQ2hhcmdlZG9mZiIgdGFtYsOpbSBwb3NzdWkgdW1hIGdyYW5kZSBxdWFudGlkYWRlIGRlIGVtcHLDqXN0aW1vcy4KCiMjIyBCb3Jyb3dlclJhdGUKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnN1bW1hcnkobGRfY2xlYW4kQm9ycm93ZXJSYXRlKQpxcGxvdChCb3Jyb3dlclJhdGUsIGRhdGEgPSBsZF9jbGVhbiwgeGxhYiA9ICJUYXhhIGRlIEp1cm9zIiwgeWxhYiA9ICJRdWFudGlkYWRlIGRlIG11dHXDoXJpb3MiLCBtYWluID0gIlRheGEgZGUgSnVyb3MgcG9yIE11dHXDoXJpbyIpCmBgYAoKUG9kZS1zZSBvYnNlcnZhciBleGlzdGVtIGFsZ3VucyB2YWxvcmVzIG1haXMgcHJlc2VudGVzIHF1ZSBzZSBkZXN0YWNhbS4gUG9yw6ltIGEgZGlzdHJpYnVpw6fDo28gbWFpcyBwb3B1bGFyIHNlIGVuY29udHJhIGVudHJlIDEwIGUgMjAlLgoKIyMjIEVzdGltYXRlZFJldHVybgoKYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc3VtbWFyeShsZF9jbGVhbiRFc3RpbWF0ZWRSZXR1cm4pCnFwbG90KEVzdGltYXRlZFJldHVybiAsIGRhdGEgPSBsZF9jbGVhbiwgeGxhYiA9ICJSZXRvcm5vIGVzdGltYWRvIiwgeWxhYiA9ICJRdWFudGlkYWRlIGRlIGVtcHLDqXN0aW1vcyIsIG1haW4gPSAiUmV0b3JubyBlc3RpbWFkbyBwb3IgcXVhbnRpZGFkZSBkZSBlbXByw6lzdGltb3MiKQoKYGBgCgpFc3NlIGdyw6FmaWNvIGNvbnNlZ3VlIHJlcHJlbnRhciBjb20gY2VydGEgZmlkZWxpZGFkZSB1bWEgcmVsYcOnw6NvIGRlIGRpc3RyaWJ1acOnw6NvIG5vcm1hbCBjb20gcmVsYcOnw6NvIGFvcyBkYWRvcyBkZSByZXRvcm5vIGVzdGltYWRvIGFwcmEgY2FkYSBlbXByw6lzdGltbyByZWFsaXphZG8uIENvbSBhIG1haW9yIGNvbmNlbnRyYcOnw6NvIGRlIHNldXMgdmFsb3JlcyBlbSBjZXJjYSBkZSAwLDklLiBDdXJpb3NvIGRlc3RhY2FyIHF1ZSBow6EgcmV0b3Jub3MgZXN0aW1hZG9zIGNvbSB2YWxvcmVzIG5lZ2F0aXZvcy4KCiMjIyBQcm9zcGVyU2NvcmUKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChsZF9jbGVhbiwgYWVzKHggPSBQcm9zcGVyU2NvcmUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgbGFicyh4ID0gIlJldG9ybm8gRXN0aW1hZG8iLCB5ID0gIlF1YW50aWRhZGUgZGUgZW1wcsOpc3RpbW9zIiwgdGl0bHRlID0gIlJldG9ybm8gZXN0aW1hZG8gcG9yIHF1YW50aWRhZGUgZGUgZW1wcsOpc3RpbW9zIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDEsMTEpLCBicmVha3MgPSBzZXEoMCwxMCwxKSkKCmBgYAoKRXNzYSByZWxhw6fDo28gdGFtYsOpbSBwYXJlY2UgcmVwcmVzZW50YXIgdW1hIGRpc3RyaWJ1acOnw6NvIG5vcm1hbC4gQ29tbyBzZSB0cmF0YSBkZSB1bWEgYXZhbGlhw6fDo28gcHLDs3ByaWEgZGEgZW1wcmVzYSBzZXLDoSBtYWlzIGludGllcmVzc2FudGUgYSBleHBsb3Jhw6fDo28gZnV0dXJhIGNvbSByZWxhw6fDo28gYSBvdXRyYXMgdmFyacOhdmVpcyBwYXJhIGRldGVybWluYXIgc2V1IGltcGFjdG8uCgojIyMgTGlzdGluZ0NhdGVnb3J5CgpFc3RhIGNhdGVnb3JpYSDDqSB0cmF0YWRhIGRlIGZvcm1hIGRpZmVyZW50ZSwgcG9yw6ltIHZhbGUgbGVtYnJhciBxdWUgYXBlc2FyIGRlIGVzdGFybW9zIGxpZGFuZG8gY29tIHVtYSBsaXN0YSBlbnVtZXJhZGEgc2VndWUgYSBzZWd1aXIgY2FkYSB1bSBkZSBzdWFzIHJlc3BlY3RpdmFzIGNhdGVnb3JpYXM6CiAgCjAgLSBOb3QgQXZhaWxhYmxlICAKMSAtIERlYnQgQ29uc29saWRhdGlvbiAgCjIgLSBIb21lIEltcHJvdmVtZW50ICAKMyAtIEJ1c2luZXNzICAKNCAtIFBlcnNvbmFsIExvYW4gIAo1IC0gU3R1ZGVudCBVc2UgIAo2IC0gQXV0byAgCjcgLSBPdGhlciAgCjggLSBCYWJ5IGFuZCBBZG9wdGlvbiAgCjkgLSBCb2F0ICAKMTAgLSBDb3NtZXRpYyBQcm9jZWR1cmUgIAoxMSAtIEVuZ2FnZW1lbnQgUmluZyAgCjEyIC0gR3JlZW4gTG9hbnMgIAoxMyAtIEhvdXNlaG9sZCBFeHBlbnNlcyAgCjE0IC0gTGFyZ2UgUHVyY2hhc2VzICAKMTUgLSBNZWRpY2FsL0RlbnRhbCAgCjE2IC0gTW90b3JjeWNsZSAgCjE3IC0gUlYgIAoxOCAtIFRheGVzICAKMTkgLSBWYWNhdGlvbiAgCjIwIC0gV2VkZGluZyBMb2FucyAgCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QobGRfY2xlYW4sIGFlcyhMaXN0aW5nQ2F0ZWdvcnkpKSArCiAgICAgICAgICAgICAgICBnZW9tX2JhcigpICsKICAgICAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMjEpLCBicmVha3MgPSBzZXEoMCwyMCwxKSkrCiAgICAgICAgICAgICAgICBsYWJzKHggPSAiQ2F0ZWdvcmlhIiwgeSA9ICJRdWFudGlkYWRlIGRlIEVtcHLDqXN0aW1vcyIsIHRpdGxlID0gIlF1YW50aWRhZGUgZGUgZW1wcsOpc3RpbW9zIHBvciBDYXRlZ29yaWEiKSAKCmBgYAoKQ29uc29saWRhw6fDo28gZGUgQ3LDqWRpdG8gw6kgbyBwcmluY2lwYWwgbW90aXZvIHBhcmEgcXVlIGFzIHBlc3NvYXMgYnVzcXVlbSBlbXByw6lzdGltb3MgbmEgUHJvc3Blci4gRGVzc2EgZm9ybWEgYSByZWxhw6fDo28gZGFzIG91dHJhcyBjYXRlZ29yaWFzIGZpY2EgbmVidWxvc2EuIFBvciBpc3NvIHNlcsOhIGNyaWFkbyB1bSBub3ZvIGdyw6FmaWNvIGlnbm9yYW5kbyBhIENvbnNvbGlkYcOnw6NvIGRlIENyw6lkaXRvIHBhcmEgcXVlIHNlamEgcG9zc8OtdmVsIGNvbXBhcmFyIGEgcmVsYcOnw6NvIGNvbSBhcyBvdXRyYXMgY2F0ZWdvcmlhcy4KCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChmaWx0ZXIobGRfY2xlYW4sIExpc3RpbmdDYXRlZ29yeSAhPSAiMSIpLCBhZXMoTGlzdGluZ0NhdGVnb3J5KSkgKwogICAgICAgICAgICAgICAgZ2VvbV9iYXIoKSArCiAgICAgICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDIxKSwgYnJlYWtzID0gc2VxKDAsMjAsMSkpKwogICAgICAgICAgICAgICAgbGFicyh4ID0gIkNhdGVnb3JpYSIsIHkgPSAiUXVhbnRpZGFkZSBkZSBFbXByw6lzdGltb3MiLCB0aXRsZSA9ICJRdWFudGlkYWRlIGRlIGVtcHLDqXN0aW1vcyBwb3IgQ2F0ZWdvcmlhIikgCmBgYAoKQWdvcmEgasOhIMOpIHBvc3PDrXZlbCBvYnNlcnZhciBxdWUgbyBzZWd1bmRvIG1vdGl2byBwYXJhIG8gZW1wcsOpc3RpbW8gbmEgUHJvc3BlciDDqSBlbmNhaXhhZG8gbmEgY2F0ZWdvcmlhICJPdXRyb3MiIG8gcXVlIMOpIHJhem/DoXZlbCBqw6EgcXVlIGVzc2Egw6kgdW1hIGNhdGVnb3JpYSBnZW7DqXJpY2EgcXVlIGVuZ2xvYmEgZGl2ZXJzYXMgb3V0cmFzIGNhdGVnb3JpYXMgbsOjbyBjYXRhbG9nYWRhcy4gRW0gc2VndWlkYSDDqSAiTWVsaG9yaWEgRG9taWNpbGlhciIsICJOZWfDs2Npb3MiIGUgIkF1dG9tw7N2ZWlzIi4KCiMjIyBPY2N1cGF0aW9uCgpgYGB7ciAsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD0xMiB9CgpnZ3Bsb3QobGRfY2xlYW4sIGFlcyh4ID0gcmVvcmRlcihPY2N1cGF0aW9uLCBPY2N1cGF0aW9uLCAgZnVuY3Rpb24oeCkrbGVuZ3RoKHgpKSkpICsKICBnZW9tX2JhcigpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIlByb2Zpc3PDo28iLCB5ID0gIlF1YW50aWRhZGUiLCB0aXRsZSA9ICJRdWFudGlkYWRlIGRlIFByb2Zpc3PDtWVzIikgCgpgYGAKCkRlbnRyZSBvcyByZXN1bHRhZG9zIG9idGlkb3Mgc2Vyw6EgZmVpdGEgdW1hIGZpbHRyYWdlbSBjb20gYXMgcHJvZmlzc8O1ZXMgY29tICJPdGhlcnMiICwgIlByb2Zlc3Npb25hbCIgZSAiIiBwb3Igc2VyZW0gYW1iw61ndWFzLgoKYGBge3IgLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9MTIgfQoKZ2dwbG90KGZpbHRlcihsZF9jbGVhbiwgT2NjdXBhdGlvbiAhPSAiT3RoZXIiICYgT2NjdXBhdGlvbiAhPSAiUHJvZmVzc2lvbmFsIiAmIE9jY3VwYXRpb24gIT0gIiIpLCBhZXMoeCA9IHJlb3JkZXIoT2NjdXBhdGlvbiwgT2NjdXBhdGlvbiwgIGZ1bmN0aW9uKHgpK2xlbmd0aCh4KSkpKSArCiAgZ2VvbV9iYXIoKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoeCA9ICJRdWFudGlkYWRlIiwgeSA9ICJQcm9maXNzw6NvIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBQcm9maXNzw7VlcyIpIAoKYGBgIAoKRW0gb3JkZW0gZGVjcmVzY2VudGUsIGEgbWFpb3IgcXVhbnRpZGFkZSBkZSBwcm9maXNzaW9uYWlzIHF1ZSBwZWdhbSBlbXByw6lzdGltb3MgZGEgUHJvc3BlciBzw6NvIEV4ZWN1dGl2b3MsIFByb2dyYW1hZG9yZXMgZSBQcm9mZXNzb3JlcywgcmVzcGVjdGl2YW1lbnRlLgoKIyMjIEVtcGxveW1lbnRTdGF0dXMKCmBgYHtyfQpzdW1tYXJ5KGxkX2NsZWFuJEVtcGxveW1lbnRTdGF0dXMpCgpnZ3Bsb3QobGRfY2xlYW4sIGFlcyhFbXBsb3ltZW50U3RhdHVzKSkgKwogIGdlb21fYmFyKCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIlN0YXR1cyBkZSBQcm9maXNzw6NvIiwgeSA9ICJRdWFudGlkYWRlIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBTdGF0dXMgZGUgUHJvZmlzc8O1ZXMiKSAKCmBgYAoKUG9kZS1zZSB2ZXJpZmljYXIgcXVlIGEgbWFpb3IgcGFydGUgZG9zIGVtcHLDqXN0aW1vcyBmb3JhbSBmZWl0b3MgY29tIHBlc3NvYXMgcXVlIGVzdGF2YW0gYXR1YWxtZW50ZSBlbXByZWdhZGFzIG5vIG1lbW9tZW50byBkbyBlbXByw6lzdGltby4gCgojIyMgQ3JlZGl0U2NvcmVSYW5nZUxvd2VyIGUgQ3JlZGl0U2NvcmVSYW5nZVVwcGVyCgpgYGB7cn0Kc3VtbWFyeShsZF9jbGVhbiRDcmVkaXRTY29yZVJhbmdlTG93ZXIpCgpnZ3Bsb3QobGRfY2xlYW4sIGFlcyhDcmVkaXRTY29yZVJhbmdlTG93ZXIpKSArCiAgZ2VvbV9iYXIoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHggPSAiVmFyaWHDp8OjbyBkZSBQb250dWHDp8OjbyBkZSBDcsOpZGl0byBtYWlzIEJhaXhhIiwgeSA9ICJRdWFudGlkYWRlIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBQZXNzb2FzIHBvciBWYXJpYcOnw6NvIGRlIFBvbnR1YcOnw6NvIGRlIENyw6lkaXRvIG1haXMgQmFpeGEiKSAKCmBgYAoKCgpgYGB7cn0Kc3VtbWFyeShsZF9jbGVhbiRDcmVkaXRTY29yZVJhbmdlVXBwZXIpCgpnZ3Bsb3QobGRfY2xlYW4sIGFlcyhDcmVkaXRTY29yZVJhbmdlVXBwZXIpKSArCiAgZ2VvbV9iYXIoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHggPSAiVmFyaWHDp8OjbyBkZSBQb250dWHDp8OjbyBkZSBDcsOpZGl0byBtYWlzIEFsdGEiLCB5ID0gIlF1YW50aWRhZGUiLCB0aXRsZSA9ICJRdWFudGlkYWRlIGRlIFBlc3NvYXMgcG9yIFZhcmlhw6fDo28gZGUgUG9udHVhw6fDo28gZGUgQ3LDqWRpdG8gbWFpcyBBbHRhIikgCmBgYAoKT2JzZXJ2YW5kbyBvcyBncsOhZmljb3MgcG9kZS1zZSBvYnNlcnZhciBxdWUgYSBkaXN0cmlidWnDp8OjbyDDqSBtdWl0byBzZW1lbGhhbnRlIHBvcsOpbSBjb20gdW0gYnJldmUgZGVzbG9jYW1lbnRvIGEgZGlyZWl0YSBlbSByZWxhw6fDo28gYSBWYXJpYcOnw6NvIG1haXMgYWx0YS4gTyBxdWUgZmF6IHNlbnRpZG8gcG9yIHF1ZSBvcyBkb2lzIGdyw6FmaWNvcyB0cmF0YW0gZGUgdW1hIG1lc21hIHZhcmnDoXZlbCBwb3LDqW0gY29tIGV4dHJlbW9zIGRpZmVyZW50ZXMuIFBvZGUtc2UgZXZpZGVuY2lhciB0YW1iw6ltIHF1ZSBhIG1haW9yIGNvbmNlbnRyYcOnw6NvIGRlIHBvbnR1YcOnw6NvIG1haXMgYmFpeGEgZmljYSBlbSB0b3JubyBkbyB2YWxvciBkZSA3MDAgZSBvIG1haXMgYWx0byBlbSB0b3JubyBkZSA3MTkuCgojIyMgQ3VycmVudERlbGlucXVlbmNpZXMKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CmdncGxvdChsZF9jbGVhbiwgYWVzKEN1cnJlbnREZWxpbnF1ZW5jaWVzKSkgKwogIGdlb21faGlzdG9ncmFtKCkrCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxOSksIGJyZWFrcyA9IHNlcSgxLDE4LDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxMTAwMCksIGJyZWFrcyA9IHNlcSgwLDExMDAwLDEwMDApKSArCiAgbGFicyh4ID0gIlF1YW50aWRhZGUgZGUgY29udGFzIGF0cmFzYWRhcyIsIHkgPSAiUXVhbnRpZGFkZSBkZSBwZXNzb2FzIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBjb250YXMgYXRyYXNhZGFzIHBvciBwZXNzb2EiKQpgYGAKUG9kZS1zZSBvYnNlcnZhciBxdWUgYSBtYWlvciBjb25jZW50cmHDp8OjbyBkZSBwZXNzb2FzIGNvbSBtdWl0YXMgZMOtdmlkYXMgc2UgZW5jb250cmEgY29tIHBvdWNhcyBjb250YXMgYXRyYXNhZGFzLiBDb20gcHJvY2Vzc28gZGUgZmlsdHJhZ2VtIHBvZGUtc2Ugb2JzZXJ2YXIgbWVsaG9yIGEgdmFyaWHDp8OjbyBjb20gbWFpcyBjb250YXMuCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQoKZ2dwbG90KGZpbHRlcihsZF9jbGVhbiwgQ3VycmVudERlbGlucXVlbmNpZXMgPiAyKSwgYWVzKEN1cnJlbnREZWxpbnF1ZW5jaWVzKSkgKwogIGdlb21faGlzdG9ncmFtKCkrCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMiwxOCksIGJyZWFrcyA9IHNlcSgzLDE4LDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxMjAwKSwgYnJlYWtzID0gc2VxKDAsMTIwMCwyMDApKSArCiAgbGFicyh4ID0gIlF1YW50aWRhZGUgZGUgY29udGFzIGF0cmFzYWRhcyIsIHkgPSAiUXVhbnRpZGFkZSBkZSBwZXNzb2FzIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBjb250YXMgYXRyYXNhZGFzIHBvciBwZXNzb2EiKQoKCmBgYApBIGZpbHRyYWdlbSBhanVkYSBhIG1vc3RyYXIgcXVlIGEgbWFpb3IgcXVhbnRpZGFkZSBkZSBwZXNzb2FzIHBvc3N1aSBtZW5vcyBjb250YXMuIFPDo28gcG91Y2FzIHBlc3NvYXMgcXVlIGVzdMOjbyBhdHJhc2FkYXMgZSBwb3NzdWVtIGRpdmVyc2FzIGNvbnRhcy4KCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpzdW1tYXJ5KGxkX2NsZWFuJEFtb3VudERlbGlucXVlbnQpCgpnZ3Bsb3QobGRfY2xlYW4sIGFlcyhBbW91bnREZWxpbnF1ZW50KSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGxhYnMoeCA9ICJRdWFudGlkYWRlIGF0cmFzYWRhIGVtIGTDs2xhciIsIHkgPSAiUXVhbnRpZGFkZSBkZSBwZXNzb2FzIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBwZXNzb2FzIGF0cmFzYWRhcyBwb3IgcXVhbnRpYSBhdHJhc2FkYSBlbSBkw7NsYXIiKQpgYGAKRmF6ZW5kbyB1bWEgYnJldmUgYW7DoWxpc2UgcG9kZS1zZSBhbmFsaXNhciBxdWUgYSBtYWlvciBwYXJ0ZSBkb3MgY2xpZW50ZXMgc2UgY29uY2VudHJhIGVtIGNsaWVudGVzIG7Do28gYXRyYXNhZG9zLgoKYGBge3J9Cgpjb3VudF9ub19kZWxpbnF1ZW50IDwtIG5yb3coZmlsdGVyKGxkX2NsZWFuLCBBbW91bnREZWxpbnF1ZW50ID09IDApKQpjb3VudF9kZWxpbnF1ZW50IDwtIG5yb3coZmlsdGVyKGxkX2NsZWFuLCBBbW91bnREZWxpbnF1ZW50ID4gMCkpCgpwcmludChjb3VudF9kZWxpbnF1ZW50Lyhjb3VudF9kZWxpbnF1ZW50K2NvdW50X25vX2RlbGlucXVlbnQpKQpgYGAKClRlbS1zZSBjZXJjYSBkZSAxMy4xJSBkb3MgY2xpZW50ZXMgYXRyYXNhZG9zLgoKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CgpnZ3Bsb3QoZmlsdGVyKGxkX2NsZWFuLCBBbW91bnREZWxpbnF1ZW50ID4gMTAwMDApLCBhZXMoQW1vdW50RGVsaW5xdWVudCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBsYWJzKHggPSAiUXVhbnRpZGFkZSBhdHJhc2FkYSBlbSBkw7NsYXIiLCB5ID0gIlF1YW50aWRhZGUgZGUgcGVzc29hcyIsIHRpdGxlID0gIlF1YW50aWRhZGUgZGUgcGVzc29hcyBhdHJhc2FkYXMgcG9yIHF1YW50aWEgYXRyYXNhZGEgZW0gZMOzbGFyIikKYGBgCgpGYXplbmRvIHVtYSBmaWx0cmFnZW0gY29tIGFwZW5hcyBhdHJhc2Fkb3MgZW0gbWFpcyBkZSAxMDAwMCBkw7NsYXJlcyDDqSBwb3Nzw612ZWwgdmVyIHF1ZSB0cmF0YW0tc2UgZGUgcG91Y2FzIHBlc3NvYXMuIFBvcnRhbnRvIGEgZ3JhbmRlIGNvbmNlbnRyYcOnw6NvIGRlIHBlc3NvYXMgc2UgZGVzdGluYSBhIGTDrXZpZGFzIG1lbm9yZXMgcXVlIDEwMDAwIGTDs2xhcmVzLgoKIyMjIERlYnRUb0luY29tZVJhdGlvCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpzdW1tYXJ5KGxkX2NsZWFuJERlYnRUb0luY29tZVJhdGlvKQoKZ2dwbG90KGRhdGEgPSBsZF9jbGVhbiwgYWVzKERlYnRUb0luY29tZVJhdGlvKSkgKwogIGdlb21faGlzdG9ncmFtKCkKCmBgYAoKQSBtYWlvciBwYXJ0ZSBkb3MgY2xpZW50ZXMgcG9zc3VpIHVtYSBwcm9wb3LDp8OjbyBkZSBkw612aWRhIGUgcmVuZGEgZGUgMC4yMiUuIFNhbHZvIGFsZ3VtYSBleGNlw6fDtWVzLiBObyBncsOhZmljbyB0b3JuYS1zZSBkaWbDrWNpbCBkZSBlbnhlcmdhciBlc3NhIHJlbGHDp8Ojby4gUG9ydGFudG8sIHNlcsOhIHV0aWxpemFkYSB1bWEgdHJhbmZvcm1hw6fDo28gbG9nYXLDrXRtaWNhIHBhcmEgZmFjaWxpdGFyIGEgdmlzdWFsaXphw6fDo28gZGVzdGUgb3V0cm9zIGNhc29zLiAKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0xNiwgZmlnLmhlaWdodD02fQpzdW1tYXJ5KGxkX2NsZWFuJERlYnRUb0luY29tZVJhdGlvKQoKZ3JhZl8xIDwtIGdncGxvdChkYXRhID0gbGRfY2xlYW4sIGFlcyhEZWJ0VG9JbmNvbWVSYXRpbykpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBsYWJzKHggPSAiUHJvcG9yw6fDo28gZGUgRMOtdmlkYSBlIFJlbmRhIiwgeSA9ICJRdWFudGlkYWRlIGRlIHBlc3NvYXMiLCB0aXRsZSA9ICJQcm9wb3LDp8OjbyBkZSBEw612aWRhIGUgUmVuZGEgcG9yIFBlc3NvYSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDEwLjEpLCBicmVha3MgPSBzZXEoMCwxMC4xLDAuNSkpIAoKZ3JhZl8yIDwtIGdncGxvdChkYXRhID0gbGRfY2xlYW4sIGFlcyhsb2cxMChEZWJ0VG9JbmNvbWVSYXRpbykrMSkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBsYWJzKHggPSAiUHJvcG9yw6fDo28gZGUgRMOtdmlkYSBlIFJlbmRhIChsb2cxMCkiLCB5ID0gIlF1YW50aWRhZGUgZGUgcGVzc29hcyIsIHRpdGxlID0gIlByb3BvcsOnw6NvIGRlIETDrXZpZGEgZW0gbG9nMTAgZSBSZW5kYSBwb3IgUGVzc29hIikKICAKZ3JpZC5hcnJhbmdlKGdyYWZfMSwgZ3JhZl8yLCBuY29sID0gMiApCgogIApgYGAKCkEgc2l0dWHDp8OjbyBkZSBhbsOhbGlzZSBzZSByZXN0cmluZ2UgYSB2YWxvcmVzIHByw7N4aW1vcyBkZSAwLjIyJSwgbWFzIG7Do28gw6kgdW0gZmF0b3IgbGltaXRhbnRlLiBFeGlzdGluZG8gY2Fzb3MgZW0gcXVlIGVzc2EgcmF6w6NvIHBvZGUgc2VyIGV4dHJhcG9sYWRhLgoKIyMjIFN0YXRlZE1vbnRobHlJbmNvbWUKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CnN1bW1hcnkobGRfY2xlYW4kU3RhdGVkTW9udGhseUluY29tZSkKCmdncGxvdChkYXRhID0gbGRfY2xlYW4sIGFlcyhTdGF0ZWRNb250aGx5SW5jb21lKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGxhYnMoeCA9ICJSZW5kYSBNZW5zYWwgRGVjbGFyYWRhIiwgeSA9ICJRdWFudGlkYWRlIGRlIHBlc3NvYXMiLCB0aXRsZSA9ICJRdWFudGlkYWRlIGRlIHBlc3NvYXMgcG9yIFJlbmRhIE1lbnNhbCBEZWNsYXJhZGEiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwyMDAwMCksIGJyZWFrcyA9IHNlcSgwLDIwMDAwLDIwMDApKQoKYGBgCgpVdGlsaXphbmRvIHVtIGNvcnRlIG3DoXhpbW8gZGUgMjAwMDAgbWlsIGTDs2xhcmVzIGNvbSByZW5kYSBtZW5zYWwgZGVjbGFyYWRhIGdlcmEtc2UgbyBncsOhZmljbyBhY2ltYS4gQ09tIG9zIGRhZG9zIGZvcm5lY2lkb3MgcG9kZS1zZSBhZmlybWFyIHF1ZSBhIG1haW9yIGNvbmNlbnRyYcOnw6NvIGRlIHJlbmRhIGVzdMOhIGVtIHRvcm5vIGRlIDUwMDAgbWlsIGTDs2FscmVzIG1lbnNhaXMuCgojIyMgTW9udGhseUxvYW5QYXltZW50CgoKYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0KCnN1bW1hcnkobGRfY2xlYW4kTW9udGhseUxvYW5QYXltZW50KQoKZ2dwbG90KGRhdGEgPSBsZF9jbGVhbiwgYWVzKE1vbnRobHlMb2FuUGF5bWVudCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBsYWJzKHggPSAiUGFyY2VsYSBkYSBEw612aWRhIE1lbnNhbCIsIHkgPSAiUXVhbnRpZGFkZSBkZSBwZXNzb2FzIiwgdGl0bGUgPSAiUXVhbnRpZGFkZSBkZSBwZXNzb2FzIHBvciBQYXJjZWxhIGRhIETDrXZpZGEgTWVuc2FsIikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMTUwMCksIGJyZWFrcyA9IHNlcSgwLDE1MDAsMTAwKSkKCmBgYAoKQSBtYWlvciBwYXJ0ZSBkYXMgZMOtdmlkYXMgbWVuc2Fpcywgbm8gZW50YW50bywgZ2lyYW0gZW0gdG9ybm8gZGUgMTYwIGUgMzAwIGTDs2xhcmVzIG1lbnNhaXMuIFF1ZSBzw6NvIHZhbG9yZXMgYWNlaXTDoXZlaXMgcXVhbnRvIGEgcG9zc2liaWxpZGFkZSBkZSBwYWdhbWVudG8uCgojIyBBbsOhbGlzZSBCYXZhcmlhZGEKCiMjIyBFbmNvbnRyYW5kbyBDb3JyZWxhw6fDtWVzCgpQYXJhIGFuYWxpc2FyIGFzIGNvcnJlbGHDp8O1ZXMgcGFyYSBhIGFuw6FsaXNlIGJpdmFyaWFkYSBzZXLDo28gZmVpdG9zIGFsZ3VucyB0ZXN0ZXMgYW50ZXMgZGUgZGVjaWRpciBxdWFpcyByZWxhw6fDtWVzIHNlcsOjbyBhcHJvZnVuZGFkYXMgYSBzZWd1aXIuCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpjb3IudGVzdChsZF9jbGVhbiRCb3Jyb3dlclJhdGUsIGxkX2NsZWFuJEVzdGltYXRlZFJldHVybikKY29yLnRlc3QobGRfY2xlYW4kUHJvc3BlclNjb3JlLCBsZF9jbGVhbiRDcmVkaXRTY29yZVJhbmdlTG93ZXIpCmNvci50ZXN0KGxkX2NsZWFuJFByb3NwZXJTY29yZSwgbGRfY2xlYW4kQ3JlZGl0U2NvcmVSYW5nZVVwcGVyKQpgYGAKCkNvcnJlbGHDp8O1ZXM6CgotIEJvcnJvd2VyUmF0ZSBlIEVzdGltYXRlZCBSZXR1cm46IDAuODI2NzMyMgotIFByb3NwZXJTY29yZSBlIENyZWRpdFNjb3JlUmFuZ2VMb3dlcjogMC4zODcwMDA2Ci0gUHJvc3BlclNjb3JlIGUgQ3JlZGl0U2NvcmVSYW5nZVVwcGVyOiAwLjM4NzAwMDYKCk11aXRhcyBkYXMgb3V0cmFzIGNvbXBhcmHDp8O1ZXMgYXBvbnRhcmFtIHZhbG9yZXMgZGUgcG9udHVhw6fDo28gZGUgY29ycmVsYcOnw6NvIG11aXRvIGJhaXhhcyBlIGZvcmFtIGRlc2NhcnRhZGFzIGUgb3V0cmFzIHV0aWxpemFtIHRpcG9zIHF1YWxpdGF0aXZvcyBlIG7Do28gcXVhbnRpdGF0aXZvcy4KClBvcnRhbnRvIGFsZ3VtYXMgZGFzIGFuw6FsaXNlcyBzZXLDo28gZmVpdGFzIGRlIGZvcm1hIGFyYml0csOhcmlhIHBhcmEgYW5hbGlzYXIgYSByZWxhw6fDo28gZGUgY2FkYSB2YXJpw6F2ZWwuCgojIyMgQm9ycm93ZXJSYXRlIGUgRXN0aW1hdGVkUmV0dXJuCgpgYGB7cn0KCmdncGxvdChkYXRhID0gbGRfY2xlYW4sIGFlcyhFc3RpbWF0ZWRSZXR1cm4sIEJvcnJvd2VyUmF0ZSkpICsKICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuMiwgc2l6ZSA9IDEsIHBvc2l0aW9uID0gJ2ppdHRlcicpICsKICBsYWJzKHggPSAiUmV0b3JubyBFc3RpbWFkbyIsIHkgPSAiVGF4YSBkZSBFbXByw6lzdGltbyIsIHRpdGxlID0gIlJldG9ybm8gRXN0aW1hZG8gcG9yIFRheGEgZGUgRW1wcsOpc3RpbW8iKQoKYGBgCgpIw6EgZG9pcyBncmFuZGVzIHBhZHLDtWVzIG9ic2VydmFkb3MgY29tIGVzdGVzIGRhZG9zLiBPIHByaW1laXJvIGRlbGVzIMOpIHF1ZSBhcyBUYXhhcyBkZSBFbXByw6lzdGltbyBlIE8gUmV0b3JubyBlc3RpbWFkbyBzZWd1ZW0gY2FtYWRhcyBsaW5lYXJlcyBlIHBhcmFsZWxhcyBkZSBmb3JtYSBiYXN0YW50ZSBzdXRpbC4gRW5xdWFudG8gYW8gbWVzbW8gdGVtcG8gaMOhIHVtYSBjb25jZW50cmHDp8OjbyBiYXN0YW50ZSBncmFuZGUgZGUgdmFsb3JlcyBhY3VtdWxhZG9zIGUgY29tIGNlcnRhIGRpdmVyZ8OqbmNpYSBkZSB2YWxvcmVzIGRlIFJldG9ybm8gRXN0aW1hZG8gZW50cmUgMC4zIGUgMC4xMSAuCgoKIyMjIExpc3RpbmdDYXRlZ29yeSBlIE9jY3VwYXRpb24KIApgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTJ9CgpnZ3Bsb3QoZGF0YSA9IGxkX2NsZWFuLCBhZXMoTGlzdGluZ0NhdGVnb3J5LCBPY2N1cGF0aW9uKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjEsIHNpemUgPSAxLCBwb3NpdGlvbiA9ICdqaXR0ZXInKSsKICBsYWJzKHggPSAiQ2F0ZWdvcmlhIGRlIEVtcHLDqXN0aW1vIiwgeSA9ICJQcm9maXNzw6NvIiwgdGl0bGUgPSAiQ2F0ZWdvcmlhIGRlIEVtcHLDqXN0aW1vIHBvciBQcm9maXNzw6NvIikgICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDIwKSwgYnJlYWtzID0gc2VxKDAsMjAsMSkpCmBgYApPIHF1ZSBtYWlzIHNlIGRlc3RhY2EgcG9yIGVzdGEgYW7DoWxpc2Ugw6kgcXVlIG8gZmF0b3IgbWFpcyByZWxldmFudGUgcGFyYSBlbXByw6lzdGltbyDDqSBhIGNhdGVnb3JpYSBkZWxhcywgcXVlIHNlZ3VlbSBvIG1lc21vIHBhZHLDo28gcGFyYSBhcyBtYWlzIGRpdmVyc2FzIHByb2Zpc3PDtWVzIGVtIG1haW9yIG91IG1lbm9zIGludGVuc2lkYWRlLiBWYWxlIGRlc3RhY2FyIHF1ZSBhcyBwcm9maXNzw7VlcyAiUHJvZmVzc2lvbmFsIiBlICJPdGhlcnMiIHBvciBzZXJlbSBtYWlzIGdlbsOpcmljYXMgZSBwb3NzdWlyZW0gZGl2ZXJzb3MgZGFkb3MgY29tIGVzdGEgZGVmaW5pw6fDo3BvLCBhcHJlc2VudGEgdW1hIGZvcnRlIG1hcmNhw6fDo28uIE91dHJhIG9ic2VydmHDp8OjbyDDqSBhIGRlIHF1ZSBFc3R1ZGFudGVzIGRlIHVtYSBmb3JtYSBnZXJhbCBuw6NvIHBvc3N1ZW0gbXVpdG9zIGVtcHLDqXN0aW1vcy4gTXVpdG8gcHJvdmF2ZWxtZW50ZSBwb3IgbW90aXZvcyBmaW5hbmNlaXJvcywgasOhIHF1ZSBhbyBlc3R1ZGFyIHRvcm5hLXNlIG1lbm9zIHByb3BlbnNvIGEgZGl2aWRpciBvIHRlbXBvIGRlIGRlZGljYcOnw6NvIGNvbSBhbGd1bSBhIGF0aXZpZGFkZSByZW11bmVyYWRhIHF1ZSBnYXJhbnRhIG8gY29icmltZW50byBkYXMgcGFyZWxhcyBkZSB1bSBlbXByw6lzdGltby4gUG9yIG91dHJvIGxhZG8sIEp1w616ZXMsIEludmVzdGlkb3JlcyB0YW1iw6ltIHPDo28gbWVub3MgcHJvcGVuc29zIGEgdGVyZW0gZW1wcsOpc3RpbW9zLiBQb3Igc3VhIHZleiwgYWNyZWRpdG8gcXVlIHBlbGEgbmF0dXJlemEgZGUgc2UgdHJhdGFyIGRlIGVtcHJlZ29zIHF1ZSByZWNlYmVtIGFsdGEgcmVtdW5lcmHDp8OjbyBow6EgYSBtZW5vciBidXNjYSBkZSBlbXByw6lzdGltb3MuCgojIyMgVGVybSBlIERlYnRUb0luY29tZVJhdGlvCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQpnZ3Bsb3QobGRfY2xlYW4sIGFlcyhEZWJ0VG9JbmNvbWVSYXRpbywgVGVybSkpICsKICBnZW9tX3BvaW50KCkgKwogIGxhYnMoeCA9ICJUYXhhIGRlIETDrXZpZGEgcG9yIFJlbmRhIiwgeSA9ICJUZW1wbyBkZSBFbXByw6lzdGltbyIsIHRpdGxlID0gIlRheGEgZGUgRMOtdmlkYSBwb3IgUmVuZGEgcG9yIFRlbXBvIGRlIEVtcnDDqXN0aW1vIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsNjApLCBicmVha3MgPSBzZXEoMCw2MCw2KSkKYGBgCgpOb3MgMyBjZW7DoXJpb3Mgb2JzZXJ2YW0tc2UgY2FyYWN0ZXLDrXN0aWNhcy4gQSBwcmltZWlyYSDDqSBxdWUgYSBtYWlvciBwYXJ0ZSBkb3MgbXV0dcOhcmlvcyBjb20gdGVtcG8gZGUgZW1wcsOpc3RpbW8gZGUgMTIgbWVzZXMgdGFtYsOpbSBwb3NzdWVtIHVtYSB0YXhhIG1lbm9yIGRlIETDrXZpZGEgcG9yIFJlbmRhLCBvIHF1ZSBzaWduaWZpY2EgcXVlIGjDoSB1bWEgcmVsYcOnw6NvIGRlIGNhcGFjaWRhZGUgZmluYW5jZWlybyBkZSBwcm92ZXIgbyBwYWdhbWVudG8gZGEgZMOtdmlkYS4gQSBzZWd1bmRhIMOpIGEgdmFyaWHDp8OjbyBncmFkdWFsIGRlIFRheGEgZGUgRMOtdmlkYSBwb3IgUmVuZGEuIFNlbmRvIGVzdGUgbyBjYXNvIG1haXMgY29tIG1haW9yIG9jb3Jyw6puY2lhcyBlIHBvciDDumx0aW1vLCBvIHRlcmNlaXJvIGNlbsOhcmlvIGVtIHF1ZSBow6EgNjAgbWVzZXMgZGUgdGVtcG8gZGUgZW1wcsOpc3RpbW8sIG1hcyBxdWUgYXByZW5zZW50YSB0YW1iw6ltIHVtYSB0YXhhIGRlIETDrXZpZGEgcG9yIFJlbmRhIG1haW9yLiAKCiMjIyBTdGF0ZWRNb250aGx5SW5jb21lIGUgUHJvc3BlclNjb3JlCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0KCmdncGxvdChkYXRhID0gbGRfY2xlYW4sIGFlcyhTdGF0ZWRNb250aGx5SW5jb21lLCBQcm9zcGVyU2NvcmUpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDUsIHNpemUgPSAxLCBwb3NpdGlvbiA9ICdqaXR0ZXInKSsKICBsYWJzKHggPSAiUmVuZGEgTWVuc2FsIERlY2xhcmFkYSIsIHkgPSAiUG9udHVhw6fDo28gZGEgUHJvc3BlciIsIHRpdGxlID0gIlJlbmRhIE1lbnNhbCBEZWNsYXJhIHBlbGEgUG9udHVhw6fDo28gZGEgUHJvc3BlciIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDIwMDAwKSwgYnJlYWtzID0gc2VxKDAsMjAwMDAsMjAwMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygxLDEwKSwgYnJlYWtzID0gc2VxKDAsMTAsMSkpCmBgYAoKUG9kZS1zZSBvYnNlcnZhciBxdWUgaMOhIHVtYSBsZXZlIGluY2xpbmHDp8OjbyBwYXJhIHF1ZSB1bWEgcXVhbnRpZGFkZSBtYWlvciBkZSBSZW5kYSBNZW5zYWwgRGVjbGFyYWRhIGFqdWRlIGEgdGVyIHVtYSBwb250dWHDp8OjbyBtYWlvciBuYSBQcm9zcGVyLCBtYXMgYWluZGEgZGV2ZW0gc2VyIGZlaXRvcyBhbsOhbGlzZXMgbWFpcyBleHRlbnNpdmFzIHBhcmEgcXVlIHBvc3NhbSBzZSBhZmlybWFyIHF1YWlzcXVlciBjb25jbHVzw7VlcyBzb2JyZSBvIHJlYWwgaW1wYWN0byBkZXN0YSB2YXJpw6F2ZWwuCgojIyMgUHJvc3BlclNjb3JlIGUgQ3JlZGl0U2NvcmVSYW5nZUxvd2VyCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OH0KZ2dwbG90KGRhdGEgPSBsZF9jbGVhbiwgYWVzKENyZWRpdFNjb3JlUmFuZ2VMb3dlciwgUHJvc3BlclNjb3JlKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjA1LCBzaXplID0gMSwgcG9zaXRpb24gPSAnaml0dGVyJykrCiAgbGFicyh4ID0gIkNyZWRpdFNjb3JlUmFuZ2VMb3dlciIsIHkgPSAiUG9udHVhw6fDo28gZGEgUHJvc3BlciIsIHRpdGxlID0gIkNyZWRpdFNjb3JlUmFuZ2VMb3dlciBwb3IgUG9udHVhw6fDo28gZGEgUHJvc3BlciIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygxLDEwKSwgYnJlYWtzID0gc2VxKDAsMTAsMSkpCmBgYAoKRXN0YSBhbsOhbGlzZSB0YW1iw6ltIG1vc3RyYSB1bWEgbGV2ZSByZWxhw6fDo28gZW50cmUgYSBDcmVkaXRTY29yZVJhbmdlTG93ZXIgZSBhIFByb3NwZXJTY29yZSBjb20gdW1hIGxldmUgdGVuZMOqbmNpYSBkZSBjcmVzY2llbW50by4KCiMjIyBQcm9zcGVyU2NvcmUgZSBDcmVkaXRTY29yZVJhbmdlVXBwZXIKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQpnZ3Bsb3QoZGF0YSA9IGxkX2NsZWFuLCBhZXMoQ3JlZGl0U2NvcmVSYW5nZVVwcGVyLCBQcm9zcGVyU2NvcmUpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDUsIHNpemUgPSAxLCBwb3NpdGlvbiA9ICdqaXR0ZXInKSsKICBsYWJzKHggPSAiQ3JlZGl0U2NvcmVSYW5nZVVwcGVyIiwgeSA9ICJQb250dWHDp8OjbyBkYSBQcm9zcGVyIiwgdGl0bGUgPSAiQ3JlZGl0U2NvcmVSYW5nZUxvd2VyIHBvciBQb250dWHDp8OjbyBkYSBQcm9zcGVyIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDEsMTApLCBicmVha3MgPSBzZXEoMCwxMCwxKSkKYGBgCgpEZSBmb3JtYSBhbsOhbG9nYSwgYSBtZXNtYSByZWxhw6fDo28gcG9kZSBzZXIgb2JzZXJ2YWRhIHF1YW5kbyBzZSB0cmF0YW0gZGFzIHZhcmnDoXZlaXMgUHJvc3BlclNjb3JlIGUgQ3JlZGl0U2NvcmVSYW5nZVVwcGVyLgoKIyMjIFByb2Zpc3PDtWVzIGUgUG9udHVhw6fDo28gUHJvc3BlcgoKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTM2fQpnZ3Bsb3QobGRfY2xlYW4sIGFlcyh4ID0gcmVvcmRlcihPY2N1cGF0aW9uLCBQcm9zcGVyU2NvcmUsICBmdW5jdGlvbih4KStsZW5ndGgoeCkpLCB5ID0gUHJvc3BlclNjb3JlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMSwxMCksIGJyZWFrcyA9IHNlcSgwLDEwLDEpKSArCiAgbGFicyh4ID0gIlByb2Zpc3PDo28iLCB5ID0gIlByb3NwZXJTY29yZSIsIHRpdGxlID0gIlByb3NwZXJTY29yZSBwb3IgUHJvZmlzc8OjbyIpIApgYGAKClVtYSBicmV2ZSBhbsOhbGlzZSBjb25zZWd1ZSBkZXN0YWNhciBhbGd1bWFzIGNhcnJlaXJhcyBxdWUgY29uc2VndWVtIG9idGVyIHBvbnR1YcOnw7VlcyBtYWlvcmVzIG5hIFByb3NwZXIgZGVudHJlIGVsYXMgZGVzdGFjYW0tc2UgUHJvZ3JhbWFkb3IsIEVuZ2VuaGVpcm8gRWxldHJpY2lzdGEsIEFkdm9nYWRvLCBEb3V0b3IsIEZhcm1hY8OqdXRpY28sIEFycXVpdGV0bywgSW52ZXN0aWRvciBlIEp1w616LiBFbSBnZXJhbCB0cmF0YW0tc2UgZGUgcHJvZmlzc8O1ZXMgYmVtIHJlbXVuZXJhZGFzLCBvIHF1ZSBwb2RlIHNlciB1bSBmYXRvciBkZXRlcm1pbmFudGUgcGFyYSBlc3RhIGFuw6FsaXNlLgoKCiMjIEFuw6FsaXNlIE11bHRpdmFyaWFkYQoKIyMjIEVzdGltYXRlZCBSZXR1cm4sIEJvcnJvd2VyUmF0ZSBlIFByb3NwZXJTY29yZQpgYGB7cn0KZ2dwbG90KGxkX2NsZWFuLCBhZXMoeCA9IEVzdGltYXRlZFJldHVybiAsICB5ID0gQm9ycm93ZXJSYXRlLCBjb2xvciA9IFByb3NwZXJTY29yZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGxhYnMoeCA9ICJFc3RpbWF0aXZhIGRlIFJldG9ybm8iLCB5ID0gIlRheGEgZGUgRW1wcsOpc3RpbW8iLCB0aXRsZSA9ICJUYXhhIGRlIEVtcHLDqXN0aW1vIHBvciBFc3RpbWF0aXZhIGRlIFJldG9ybm8gcG9yIFByb3NwZXIgU2NvcmUiLCBjb2xvciA9ICJQcm9zcGVyIFNjb3JlIikgCiAgCmBgYAoKQ29tcGFyYW5kbyBhZ29yYSBhIGFuw6FsaXNlIGJpdmFyaWFkYSBkZSBCb3Jyb3dlciBSYXRlIGUgRXN0aW1hdGVkIFJldHVybiBjb20gbyBQcm9zcGVyU2NvcmUgw6kgcG9zc8OtdmVsIGVueGVyZ2FyIHVtYSBncmFkYcOnw6NvIGJhc3RhbnRlIGludGVyZXNzYW50ZSBwYXJhIGFzIHJlbGHDp8O1ZXMgZGUgQm9ycm93ZXIgUmF0ZSBlIEVzdGltYXRlZCBSZXR1cm4uIFBvZGUtc2UgY29uY2x1aXIgcXVlIHVtIGRvcyBmYXRvcmVzIG1haXMgcmVsZXZhbnRlcyBwYXJhIGEgZGlmZXJlbmNpYcOnw6NvIMOpIGEgbm90YSBkYSBQcm9zcGVyU2NvcmUgcXVlIGNvbmNlbnRyYSBtYWlvcmVzIHBvbnR1YcOnw7VlcyBxdWFudG8gbWFpb3IgYSBFc3RpbWF0aXZhIGRlIFJldG9ybm8sIG8gcXVlIHRhbWLDqW0gdmlhYmlsaXphIHVtYSBUYXhhIGRlIEVtcHLDqXN0aW1vIE1lbm9yLgoKCiMjIyBTdGF0ZWRNb250aGx5SW5jb21lLCBFc3RpbWF0ZWRSZXR1cm4gZSBQcm9zcGVyU2NvcmUKCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9MTZ9CgpnZ3Bsb3QoZGF0YSA9IGxkX2NsZWFuLCBhZXMoeCA9IFN0YXRlZE1vbnRobHlJbmNvbWUsIEVzdGltYXRlZFJldHVybiwgY29sb3IgPSBQcm9zcGVyU2NvcmUpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSwgc2l6ZSA9IDEsIHBvc2l0aW9uID0gJ2ppdHRlcicpKwogIGxhYnMoeCA9ICJSZW5kYSBNZW5zYWwgRGVjbGFyYWRhIiwgeSA9ICJFc3RpbWF0aXZhIGRlIFJldG9ybm8iLCB0aXRsZSA9ICJSZW5kYWwgTWVuc2FsIERlY2xhcmFkYSBwb3IgRXN0aW1hdGl2YSBkZSBSZXRvcm5vIHBvciBQcm9zcGVyU2NvcmUiKSAgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwyMDAwMCksIGJyZWFrcyA9IHNlcSgwLDIwMDAwLDIwMDApKQpgYGAKCk5lc3RhIGFuw6FsaXNlIHBvZGUtc2UgY2hlZ2FyIGEgY29uY2x1c8OjbyBxdWUgdmFsb3JlcyBkZSB0YXhhIGRlIHJldG9ybm8gbmVnYXRpdmFzIGltcGFjdGFtIG5hIFByb3NwZXJTY29yZSBzaWduaWZpY2F0aXZhbWVudGUuIE7Do28gc2lnbmlmaWNhIHF1ZSBxdWFudG8gbWFpb3IgYSB0YXhhIGRlIHJldG9ybm8gbWFpb3IgYSBwb250dWHDp8OjbyBkYSBQcm9zcGVyU2NvcmUsIGNvbW8gcG9kZS1zZSBldmlkZW5jaWFyIHBlbGEgbnV2ZW0gbWVzY2xhZGEgZGUgZGFkb3MgZW50cmUgdGF4YXMgc3VwZXJpb3JlcyBhIDAgZSBpbmZlcmlvcmVzIGEgMC4yLiBQb3LDqW0sIHBhcmEgdGF4YXMgYWNpbWEgZGUgMC4yIGEgUHJvc3BlclNjb3JlIHNlbXByZSBhcHJlc2VudGEgYm9hcyBwb250dWHDp8O1ZXMuIApBZ29yYSBzb2JyZSBhIFJlbmRhIE1lbnNhbCBEZWNsYXJhZGEgbsOjbyBwYXJlY2UgdGVyIHRhbnRyYSBpbmZsdcOqbmNpYSBuYSBQcm9zcGVyU2NvcmUuIAoKIyMjIExpc3RpbmdDYXRlZ29yeSwgRGVidFRvSW5jb21lUmF0aW8sIFByb3NwZXJTY29yZQoKYGBge3IgIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRhID0gbGRfY2xlYW4sIGFlcyh4ID0gTGlzdGluZ0NhdGVnb3J5LCBEZWJ0VG9JbmNvbWVSYXRpbywgY29sb3IgPSBQcm9zcGVyU2NvcmUpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSwgc2l6ZSA9IDEsIHBvc2l0aW9uID0gJ2ppdHRlcicpKwogIGxhYnMoeCA9ICJDYXRlZ29yaWFzIiwgeSA9ICJSYXrDo28gZGUgRMOtdmlkYSBlIFJlbmRhIE1lbnNhbCIsIHRpdGxlID0gIkNhdGVnb3JpYXMgcG9yIFJhesOjbyBkZSBEw612aWRhIGUgUmVuZGEgTWVuc2FsIFBvciBQcm9zcGVyU2NvcmUiKSAgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMjApLCBicmVha3MgPSBzZXEoMCwyMCwxKSkgCgoKYGBgCgpFc3RhIGFuw6FsaXNlIG7Do28gY29uc2VndWUgYXRpbmdpciBuZW5odW1hIGNvbmNsdXPDo28gcG9yIGFwcmVzZW50YXIgdW1hIGRpc3RyaWJ1acOnw6NvIGJhc3RhbnRlIGJhZ3Vuw6dhZGEgZGEgUHJvc3BlclNjb3JlLgoKIyMgR3LDoWZpY29zIEZpbmFpcyBlIFJlc3VtbwoKIyMjIAoKIyMjIFJlbGHDp8OjbyBkYSBSYXrDo28gZGEgRMOtdmlkYSBwb3IgUmVuZGEgTWVuc2FsIHBvciBUYXhhIGRlIEVtcHLDqXN0aW1vIHBhcmEgYSBQcm9zcGVyIFNjb3JlCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QobGRfY2xlYW4sIGFlcyh4ID0gRGVidFRvSW5jb21lUmF0aW8sIHkgPSBCb3Jyb3dlclJhdGUsIGNvbG9yID0gUHJvc3BlclNjb3JlKSkrCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMikgKwogIGdlb21fc21vb3RoKGNvbG9yID0gIiNGRjY2NjYiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC4wNCwwLjM2KSwgYnJlYWtzID0gc2VxKDAuMDQsMC4zNiwwLjAyKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSksIGJyZWFrcyA9IHNlcSgwLDEsMC4yMCkpICsKICBsYWJzKHggPSAiUmF6w6NvIGRlIETDrXZpZGEgcG9yIFJlbmRhIE1lbnNhbCIsIAogICAgICAgeSA9ICJUYXhhIGRlIEVtcHLDqXN0aW1vIiwgCiAgICAgICB0aXRsZSA9ICJSZWxhw6fDo28gZGEgUmF6w6NvIGRhIETDrXZpZGEgcG9yIFJlbmRhIE1lbnNhbCBwb3IgVGF4YSBkZSBFbXByw6lzdGltbyBwYXJhIGEgUHJvc3BlciBTY29yZSIpICsKICB0aGVtZV9saWdodCgpCiAgCmBgYAoKRXN0ZSBncsOhZmljbyBlbnZvbHZlIGEgcmVsYcOnw6NvIGVudHJlIGEgUmF6w6NvIGRhIETDrXZpZGEgcG9yIFJlbmRhIE1lbnNhbCwgcXVlIGFvIGxvbmdvIGRlIHRvZGEgZXN0YSBhbsOhbGlzZSBmb2kgY29uc2lkZXJhZGEgdW1hIHZhcmnDoXZlbCBiYXN0YW50ZSBpbXBvcnRhbnRlIHBhcmEgZGV0ZXJtaW5hciBhIHBvc3NpYmlsaWRhZGUgZGUgY2FkYSBtdXR1w6FyaW8gc2VyIGNhcGF6IGRlIHF1aXRhciBzZXUgZW1wcsOpc3RpbW8sIGNvbSBhIFRheGEgZGUgRW1wcsOpc3RpbW8sIHF1ZSDDqSBhIHRheGEgZGV0ZXJtaW5hZGEgcGFyYSBxdWVtIGVzdMOhIGVtcHJlc3RhbmRvIGVzdGUgZGluaGVpcm8gYW8gbXV0dcOhcmlvLiBFc3NhIHJlbGHDp8OjbyBjb25zZWd1ZSBjcmlhciB1bSBncmFkaWVudGUgY29tIGEgcG9udHVhw6fDo28gZGEgUHJvc3BlciBwYXJhIGNhZGEgbXV0dcOhcmlvLiAKCkEgcHJpbmPDrXBpbyDDqSBwb3Nzw612ZWwgZW54ZXJnYXIgcXVlIGjDoSB1bWEgbWFpb3IgY29uY2VudHJhw6fDo28gZGUgcG9udHVhw6fDo28gbWFpcyBhbHRhIGFvIHJlZHV6aXIgYSBUYXhhIGRlIEVtcHLDqXN0aW1vLiBQb3LDqW0sIG7Do28gc2UgdG9ybmEgZGlzdGludG8gdMOjbyBmYWNpbG1lbnRlIHNlIGEgUmF6w6NvIGRlIETDrXZpZGEgcG9yIFJlbmRhIE1lbnNhbCB0YW1iw6ltIGluZmx1ZW5jaWEgdGFudG8gYSBQb250dWHDp8OjbyBkYSBQcm9zcGVyLiBQb3IgaXNzbywgdG9ybmEtc2UgbmVjZXNzw6FyaW8gbyB1c28gZGEgcmV0YSBwYXJhIGVueGVyZ2FyIGEgdGVuZMOqbmNpYSBkZXNzZXMgZGFkb3MuIAoKQSBjb25jbHVzw6NvIMOpIHF1ZSBtYWlvciBzZXLDoSBhIFBvbnR1YcOnw6NvIGRhIFByb3NwZXIgcXVhbnRvIG1lbm9yIGZvciBhIGEgcmF6w6NvIGRhIGTDrXZpZGEgcG9yIHJlbmRhIG1lbnNhbCBkbyBtdXR1w6FyaW8gZSBxdWFudG8gbWVub3IgYSB0YXhhIGRlIGVtcHLDqXN0aW1vLgoKIyMjIFJlbmRhIE1lbnNhbCBEZWNsYXJhZGEsICBFc3RpbWF0aXZhIGRlIFJldG9ybm8sIFByb3NwZXJTY29yZQoKYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTE4LCBmaWcuaGVpZ2h0PTE2fQoKZ2dwbG90KGRhdGEgPSBsZF9jbGVhbiwgYWVzKHggPSBTdGF0ZWRNb250aGx5SW5jb21lLCBFc3RpbWF0ZWRSZXR1cm4sIGNvbG9yID0gUHJvc3BlclNjb3JlKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIHNpemUgPSAxLCBwb3NpdGlvbiA9ICdqaXR0ZXInKSArCiAgbGFicyh4ID0gIlJlbmRhIE1lbnNhbCBEZWNsYXJhZGEiLCB5ID0gIkVzdGltYXRpdmEgZGUgUmV0b3JubyIsIHRpdGxlID0gIlJlbmRhbCBNZW5zYWwgRGVjbGFyYWRhIHBvciBFc3RpbWF0aXZhIGRlIFJldG9ybm8gcG9yIFByb3NwZXJTY29yZSIpICArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDIwMDAwKSwgYnJlYWtzID0gc2VxKDAsMjAwMDAsMjAwMCkpCgpgYGAKCkEgYW7DoWxpc2UgZGUgUmVuZGEgTWVuc2FsIERlY2xhcmFkYSBlIEVzdGltYXRpdmEgZGUgUmV0b3JubywgYXByZXNldGFyYW0gcmVzdWx0YWRvcyBiYXN0YW50ZSBpbnRlcmVzc2FudGVzIHBhcmEgYSBhbsOhbGlzZSBkbyBTY29yZSBkYSBQcm9zcGVyLiBJbmljaWFsbWVudGUgcG9kZW1vcyBhZmlybWFyIHF1ZSBuw6NvIGjDoSBpbmZsdcOqbmNpYSBkYSByZWxhw6fDo28gZGFzIGR1YXMgdmFyacOhdmVpcyBlbSByZWxhw6fDo28gw6AgcG9udHVhw6fDo28gZGEgUHJvc3Blci4gUG9yw6ltLCBvbGhhbmRvIGN1aWRhZG9zYW1lbnRlLCDDqSBwb3Nzw612ZWwgZW54ZXJnYXIgcXVlIGV4aXN0ZW0gdmFsb3JlcyBsaW1pdGFudGVzIHBhcmEgYSBlc3RpbWF0aXZhIGRlIHJldG9ybm8gcXVlIGNyaWFtIGZhaXhhcyBxdWUgcG9kZW0gY3JpYXIgc2VwYXJhw6fDtWVzIGVudHJlIDMgw6FyZWFzIGRpc3RpbnRpdGFzLiBBIHByaW1laXJhIGZhaXhhIGRlbGltaXRhIHVtYSB0YXhhIGRlIHJldG9ybm8gYWNpbWEgYW8gdmFsb3IgZGUgMC4xOCBxdWUgcHJlZG9taW5hbnRlbWVudGUgcG9zc3VpIGFwZW5hcyBtdXR1w6FyaW9zIGNvbSBwb250dWHDp8O1ZXMgbWFpcyBhbHRhcyBuYSBQcm9zcGVyU2NvcmUuIEEgZmFpeGEgaW5mZXJpb3IgZGUgLTAuMDIgcGFyYSBiYWl4byBhcHJlc2VudGEgcHJlZG9taW5hbnRlbWVudGUgbXV0dcOhcmlvcyBjb20gYmFpeGFzIHBvbnR1YcOnw7VlcyBuYSBQcm9zcGVyU2NvcmUuIEVucXVhbnRvIGEgY2FtYWRhIGNlbnRyYWwgc2UgZW5jb250cmEgdW1hIGZhaXhhIGNvbSB2YWxvcmVzIGRpc3RpbnRvcyBlIGJhc3RhbnRlIG1pc3R1cmFkb3MgZW50cmUgc2kuIFNlbSBwb2RlciBhZmlybWFyIHVtYSByZWxhw6fDo28gY29tIGEgcmVuZGEgbWVuc2FsIGRlY2xhcmFkYS4gTXVpdG8gcHJvdmF2ZWxtZW50ZSBwb3Igc2VyIG11aXRvIG1haXMgcHJvdsOhdmVsIGRlIHNlIGRldGVybWluYXIgdW1hIHJlbGHDp8OjbyBicnV0YSBkYSBwb250dWHDp8OjbyBkYSBQcm9zcGVyIHF1YW5kbyBjb21hcHJhIGFvIGdyw6FmaWNvIGRhIGFuw6FsaXNlIGFudGVyaW9yLCBqw6EgcXVlIGVzdGFyaWEgbGlkYW5kbyBjb20gYSB2YXJpw6F2ZWwgZW0gZnVuw6fDo28gZGEgUmF6w6NvIGVudHJlIGEgRMOtdmlkYSBlIGEgUmVuZGEgbWVuc2FsIGRvIG11dHXDoXJpby4KUG9ydGFudG8sIG1haW9yIHJlbmRhIG7Do28gc2lnbmlmaWNhIG5hZGEgcGFyYSBhIFBvbnR1w6fDo28gZGEgUHJvc3BlciwgbWFzIHNpbSBhIHJlbGHDp8OjbyBkZXNzYSByZW5kYSBjb20gYSBkw612aWRhIGVtIHNpLgoKIyMjIERlYnRUb0luY29tZVJhdGlvLCBPY2N1cGF0aW9uLCBQcm9zcGVyU2NvcmUKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KZ2dwbG90KGRhdGEgPSBsZF9jbGVhbiwgYWVzKHggPSBEZWJ0VG9JbmNvbWVSYXRpbywgeSA9IHJlb3JkZXIoT2NjdXBhdGlvbiwgZGVzYyhPY2N1cGF0aW9uKSksIGNvbG9yID0gUHJvc3BlclNjb3JlKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjI1LCBzaXplID0gMSwgcG9zaXRpb24gPSAnaml0dGVyJykgKwogIGxhYnMoeCA9ICJSYXrDo28gZW50cmUgRMOtdmlkYSBlIFJlbmRhIE1lbnNhbCIsIHkgPSAiUHJvZmlzc8OjbyIsIHRpdGxlID0gIlJhesOjbyBlbnRyZSBEw612aWRhIGUgUmVuZGEgTWVuc2FsIHBvciBQcm9maXNzw6NvIHBvciBQb3JzcGVyU2NvcmUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxKSwgYnJlYWtzID0gc2VxKDAsMSwwLjIpKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnMgPSByYWluYm93KDUpKQpgYGAKQSBhbsOhbGlzZSBkZSBQcm9maXNzw7VlcyBwb3IgUmVuZGEgTWVuc2FsIERlY2xhcmFkYSB2YWkgcG9zc3VpciB1bWEgY2VydGEgZGlzdHJpYnVpw6fDo28gcXVlIGFjb21wYW5oYXLDoSBjYWRhIFByb2Zpc3PDo28uIEFnbG9tZXJhbmRvIGVzc2FzIGluZm9ybWHDp8O1ZXMgY29tIGEgcG9udHVhw6fDo28gZGEgUHJvc3BlciBwb2RlLXNlIG9ic2VydmFyIHF1ZSBtYWlvcmVzIHBvbnR1YcOnw7VlcyBkYSBQcm9zcGVyIGVzdMOjbyBkaXN0cmlidcOtZGFzIGVudHJlIHRvZGFzIGFzIHByb2Zpc3PDtWVzIHBvcsOpbSwgYWxndW1hcyBjb25jZW50cmFtIHVtYSBxdWFudGlkYWRlIG1haW9yLiBFcmEgZGUgc2UgZXNwZXJhciBxdWUgYSBSYXrDo28gZGEgRMOtdmlkYSBlIFJlbmRhIE1lbnNhbCBmb3NzZW0gZmF0b3JlcyBmb3J0ZXMgcGFyYSBlc3NhIHBvbnR1YcOnw6NvLCBwb3LDqW0sIHBvZGUtc2UgZW54ZXJnYXIgcXVlIGVtIGFsZ3VtYXMgcHJvZmlzc8O1ZXMgZXhpc3RlbSBtdXR1w6FyaW9zIGNvbSBlc3NhIHJhesOjbyBwcsOzeGltYSBkZSAwLjIgcXVlIHRhbWLDqW0gYXByZW5zZW50YW0gcG9udHVhw6fDtWVzIGFsdGFzIG5hIFByb3NwZXIuIAoKCiMjIFJlZmxleMOjbwoKRXN0ZSBwcm9qZXRvIGZvaSBiYXN0YW50ZSBpbnRlcmVzc2FudGUgZSB0YW5nZW5jaWFsbWVudGUgaW5jZW50aXZhIG8gZXN0dWRhbnRlIGEgY29tcHJlZW5kZXIgb3MgZGFkb3MgcXVlIGVzdMOjbyBzZW5kbyB0cmFiYWxoYWRvcy4gUG9yIGVzdGUgbWVzbW8gbW90aXZvLCBhIHByaW1laXJhIGRpZmljdWxkYWRlIGVuY29udHJhZGEgZm9pIGVudGVuZGVyIGNhZGEgdmFyacOhdmVsIGRlIG1hbmVpcmEgY29ycmV0YSwgasOhIHF1ZSBldSBuw6NvIHBvc3N1byBiYWNrZ3JvdW5kIGVtIGNvbW8gZW1wcsOpc3RpbW9zIGZ1bmNpb25hbSwgaXNzbyBhbGlhZG8gYW9zIHRlcm1vcyB0b2RvcyBlbSBpbmdsw6pzIGFncmVnb3UgbXVpdG8gY29uaGVjaW1lbnRvIGJ1c2NhbmRvIGVudGVuZGVyIGNvbW8gdHVkbyBmdW5jaW9uYXZhLiBVbWEgZ3JhbmRlIGFqdWRhIGZvaSBhIFtwbGFuaWxoYSBleHBsaWNhdGl2YSBdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFnRHlpX0w0VXZJckxURUM2V3JpNW5iYU1ta0dtTFFCay1ZeDN6MFhERXRJL2VkaXQjZ2lkPTApIGRlc2NyZXZlbmRvIGNhZGEgdmFyacOhdmVsIGUgc3VhcyBwZWN1bGlhcmlkYWRlcy4KCkVtIHNlZ3VpZGEgZm9pIHVtIGdyYW5kZSBleGVyY8OtY2lvIGxpZGFyIGNvbSBlc3RlIG7Dum1lcm8gZGUgdmFyacOhdmVpcyBjb20gdGFudG9zIHRpcG9zIGRpZmVyZW50ZXMgZSBidXNjYXIgY29tcHJlZW5kZXIgYSBtZWxob3IgZm9ybWEgZGUgbGlkYXIgY29tIGFzIHZhcmnDoXZlaXMgZXNjb2xoaWRhcy4gCgpBZ29yYSBxdWUgbyBwcm9jZXNzbyBkZSBhbsOhbGlzZSBjaGVnb3UgYW8gZmltIHNvYnJhIHVtIHBvdWNvIGRlIGN1cmlvc2lkYWRlIGRlIG91dHJhcyBjb25jbHVzw7VlcyBxdWUgcG9kZXJpYW0gc2VyIG9idGlkYXMgbGlkYW5kbyBjb20gbWFpcyB2YXJpw6F2ZWlzLiBEYXMgODEgdmFyacOhdmVpcyBwcmVzZW50ZXMgbm8gY29uanVudG8gZGUgZGFkb3MgZm9yYW0gdXRpbGl6YWRhcyBhcGVuYXMgMTYgZGVsYXMuIERlc3NhIGZvcm1hIHNvYnJhbSBtdWl0YXMgcG9zc2liaWxpZGFkZXMgZGUgYW7DoWxpc2VzIHF1ZSBwb2RlcmlhbSBzZXIgZmVpdGFzLgoKCgo=